CAS操作本质是CPU硬件指令(如x86的cmpxchg),Java通过Unsafe的native方法调用JVM C++层,再经JNI映射到底层汇编,配合lock前缀和内存屏障实现原子性与可见性。

Java 中的 CAS(Compare-And-Swap)操作,例如 Unsafe.compareAndSwapObject,其底层并非直接由 Java 实现,而是通过 JVM 的本地方法(JNI)调用 C++ 层的原子指令。它最终依赖 CPU 提供的硬件级原子指令(如 x86 上的 cmpxchg),而非软件锁或轮询模拟。
Unsafe 方法如何连接到 JVM C++ 层
Unsafe.compareAndSwapObject 是一个 native 方法,在 Unsafe.java 中声明为:
对应 JNI 绑定在 JVM 源码中(如 OpenJDK 17 的 unsafe.cpp),注册为:UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject)。该函数解析传入的 Java 对象、偏移量和期望值,再委托给平台相关的原子操作封装。
x86-64 平台上的核心汇编指令:cmpxchg
JVM 在 x86-64 上实际生成的原子操作,本质是 cmpxchg 指令(Compare and Exchange):
立即学习“Java免费学习笔记(深入)”;
-
cmpxchg [addr], new_val会将rax(隐含的 accumulator)与[addr]处的值比较;相等则写入new_val,并清零 ZF 标志位;否则将[addr]值加载进rax,ZF 置 1。 - JVM 封装层(如
atomic_linux_x86.inline.hpp)会用lock cmpxchg前缀确保该指令在多核间全局原子——lock会触发总线锁或缓存一致性协议(MESI)来锁定缓存行。 - 返回值即 CPU 的 ZF 标志,JVM 将其转为 Java 的
boolean:ZF=0 → true(交换成功),ZF=1 → false(失败)。
对象字段偏移与内存模型的协同
CAS 成功的前提不仅是硬件原子性,还需 JVM 内存模型配合:
- 传入的
offset来自Unsafe.objectFieldOffset,它由 JVM 在类初始化时计算字段相对于对象起始地址的字节偏移(考虑对象头、对齐填充等)。 - JVM 保证该偏移访问的是可被
cmpxchg安全操作的内存位置(例如,不会跨缓存行;对齐要求满足)。 - Java 的 happens-before 规则规定:成功的 CAS 写操作对后续读该变量的线程构成先行发生关系,这背后由 CPU 的内存屏障(如
lock指令自带的 full barrier)和 JVM 插入的内存屏障共同保障。
不同平台的实现差异
同一 CAS 语义在不同 CPU 架构上由不同指令实现:
-
Aarch64:使用
ldaxr(load-acquire exclusive)、stlxr(store-release exclusive)配对实现;失败时需重试循环(LL/SC 模式)。 -
PowerPC:依赖
lwarx+stwcx.指令序列,同样基于条件存储尝试。 - JVM 在
atomic_<os>_<cpu>.inline.hpp</cpu></os>中提供统一 C++ 接口(如Atomic::cmpxchg),屏蔽底层差异,上层代码无需关心指令细节。


















