跳转至

CAS 底层 CPU 指令:cmpxchg

一、Java 层的 CAS

U.compareAndSwapInt(o, offset, expect, update);

二、JVM 层

JVM 把它编译成 CPU 指令。x86 上是 lock cmpxchg

lock cmpxchg [addr], new_value

语义

如果 EAX == [addr]:
    ZF = 1
    [addr] = new_value
否则:
    ZF = 0
    EAX = [addr]

EAX 是默认寄存器,存期望值。

三、lock 前缀

lock 前缀保证: 1. 原子性:整个指令执行期间锁缓存行(MESI)。 2. 内存屏障:禁止重排。 3. 写回内存。

四、为什么 CAS 是原子的

  • cmpxchg 本身是一条指令。
  • lock 前缀锁缓存行,其他核不能同时改。
  • 硬件保证读-比较-写一气呵成。

五、其他架构

  • x86:lock cmpxchg
  • ARM:ldrex / strex(Load Exclusive / Store Exclusive)
  • RISC-V:lr.d / sc.d

原理一样:独占加载 + 条件存储。

六、自旋

JVM 的 getAndAddInt 是 do-while 自旋:

do {
    v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v + delta));

CAS 失败说明被别的线程改了,重新读再试。

总结

CAS = CPU 一条原子指令 + Java 层自旋重试。不是"无锁",是"用户态无锁",底层还是硬件锁(缓存行锁)。