CAS的原子性由CPU硬件指令cmpxchg直接保障,该指令在x86架构中以“读-比-写”三步不可分割方式执行,多核下通过缓存锁(MESI协议)或总线锁(LOCK#信号)确保独占访问,Java层通过Unsafe调用最终映射至此指令。

CAS 的原子性不是靠 Java 或 JVM 实现的,而是由 CPU 硬件直接保障的。核心就在 cmpxchg 这条汇编指令本身——它在 x86 架构上是一条“不可分割”的原语指令。
cmpxchg 指令如何做到原子执行
这条指令执行的是“读-比-写”三步动作,但硬件确保这三步不会被中断或交错:
- 把累加器(如 EAX)的值和内存地址 V 处的值比较;
- 如果相等,就把源操作数(新值 N)写入 V;
- 如果不等,就把 V 当前的值加载回 EAX,同时清零 ZF(零标志位)。
整个过程在 CPU 内部完成,中间不响应中断、不切换线程、也不允许其他核心并发修改同一缓存行——这是由底层硬件协议保证的。
多核环境下靠什么避免干扰
单核 CPU 上,cmpxchg 本身已天然原子;但在多核场景中,需额外机制防止多个 CPU 同时改同一内存位置:
立即学习“Java免费学习笔记(深入)”;
- 当操作目标是内存地址(而非寄存器)时,现代 x86 处理器会自动触发缓存一致性协议(MESI),将该缓存行置为独占(Exclusive)状态,再执行 cmpxchg;
- 若缓存行未命中或跨缓存同步困难,CPU 会升级为总线锁(LOCK# 信号),短暂阻塞其他核心访问总线——但这只是兜底策略,实际中绝大多数情况走缓存锁,开销极低;
- JVM 在生成 cmpxchg 时,会根据运行环境决定是否显式加上 LOCK 前缀:多处理器必加,单处理器可省略。
Java 层怎么连到这条指令
你写的 atomicInteger.compareAndSet(5, 2019) 最终会走到:
- Java 层调用
Unsafe.compareAndSwapInt(); - JVM 将其翻译为平台相关的本地代码(C++),最终发出
lock cmpxchg指令; - 这条指令交由 CPU 执行,结果通过返回值(ZF 标志位)反馈给上层——成功则 ZF=1,失败则 ZF=0,Java 再据此返回 true/false。
为什么不能靠软件模拟出原子性
有人想用“先读再判断再写”来手动实现 CAS,但注定失败:
- 两次内存访问之间存在时间窗口,其他线程可能插入修改;
- 即使加 volatile,也只能保证可见性,无法阻止“读-改-写”三步被拆开;
- 只有硬件级指令才能把“比较 + 条件写入”封装成一个不可打断的单元——这是操作系统和高级语言都无法越过的底层边界。


















