cas 实现无锁原子操作,依靠 cpu 硬件指令(如 x86 的 cmpxchg)将“读值—比对—写入”三步一次性完成,具备硬件级原子性、隐式内存屏障和极小开销;java 通过 unsafe 封装为乐观自旋重试机制,避免线程挂起与上下文切换,解决 volatile 无法保证的“读-改-写”原子缺口。

CAS 实现无锁原子操作,靠的不是 JVM 层面的锁机制,而是把“读值—比对—写入”这三步压进一条 CPU 硬件指令里一次性完成,中间不被打断、不被调度、不依赖线程挂起与唤醒。
核心是硬件级原子指令
CAS 不是 Java 语言自己实现的逻辑,它背后由 CPU 直接支持。比如 x86 架构用 CMPXCHG 指令:把寄存器里的预期值和内存地址上的当前值做比较,相等就写入新值,否则把内存最新值加载回寄存器。整个过程由 CPU 自动加缓存锁(cache lock),只锁定对应缓存行,开销极小;必要时才升级为总线锁。
- 这条指令执行时隐式插入内存屏障,禁止编译器和 CPU 对相关读写重排序
- JVM 无法靠软件模拟这种原子性,必须借力硬件
- Java 中通过 Unsafe.compareAndSwapInt 等 native 方法暴露该能力
Java 层封装成乐观尝试模式
AtomicInteger.incrementAndGet() 这类方法,表面看是自旋循环,本质是不断调用 CAS 尝试更新:
- 先用 volatile 读取当前值(保证看到最新)
- 算出新值(如 +1)
- 调用 CAS:如果内存值仍等于刚才读到的旧值,就成功替换;否则失败,返回 false
- 失败后不阻塞,而是重新读、再算、再试——这就是“乐观”策略
为什么叫“无锁”却能保证原子性
它不使用 monitor、不触发线程挂起、不产生上下文切换。线程始终在运行,只是在关键更新点上依赖硬件指令的不可分割性。只要没有其他线程在 CAS 执行间隙修改目标内存位置,整个操作就天然具备原子语义。
- 不是“没锁”,而是“不用传统意义上的锁”
- 失败不等待,而是主动重试,把同步责任交给调用方逻辑
- 适合冲突概率低的场景,比如计数器、状态标记、单变量引用切换
它解决的是“读-改-写”的原子缺口
volatile 能保证可见性,但不能防止两个线程同时读到相同旧值、各自+1后再写回,造成丢失更新。CAS 把“是否还能写”这个判断和“写什么”绑在一起执行,堵住了这个窗口。
- 例如:两个线程都读到 count=5,各自算出6,若直接写入就会变成6而不是7
- CAS 要求“只有当我读到的还是5,才允许我写6”,第二个线程发现内存已是6,就会重来
- 最终结果一定准确,且全程无锁参与
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











