Java中CAS底层通过Unsafe的native方法,由JVM编译为x86的cmpxchg或ARM的ldxr/stxr等硬件原子指令实现;依赖volatile保证可见性、CPU指令保障原子性,且JVM插入内存屏障并校验内存安全。

Java 中的 CAS(Compare-And-Swap)底层并不直接“调用硬件原语”,而是通过 Unsafe 类封装的本地方法,最终由 JVM 在运行时编译为特定 CPU 架构支持的原子指令(如 x86 的 cmpxchg、ARM 的 ldxr/stxr),从而借助硬件能力实现无锁原子操作。
Unsafe 提供的是 JVM 层的原子操作入口
Unsafe 是 JDK 内部类,其核心 CAS 方法(如 compareAndSwapInt、compareAndSwapObject)是 native 方法,声明如下:
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);
这些方法不自己实现逻辑,而是将参数(对象、内存偏移量、期望值、新值)交给 JVM。JVM 根据当前平台和运行模式(解释执行 / JIT 编译)决定如何处理:
- 解释执行时:进入 JVM 内部 C++ 实现,调用平台相关的原子库(如 Linux 下的
atomic_cmpxchg) - JIT 编译后(热点代码):HotSpot 会将该调用内联并替换为一条或多条 CPU 原子指令(如 x86-64 的
lock cmpxchg),避免函数调用开销
CAS 能生效依赖 CPU 级别的原子保证
硬件本身不提供“CAS 指令”这种高级语义,而是提供带“原子读-改-写”能力的基础原语,常见有:
- x86/x64:
cmpxchg(配合lock前缀保证缓存一致性,在多核下触发 MESI 协议) - ARM64:
ldxr(load-exclusive) +stxr(store-exclusive),成对使用构成 LL/SC(Load-Linked/Store-Conditional)范式 - RISC-V:
lr.w/sc.w,同样是 LL/SC 机制
JVM 在生成汇编时,会根据目标 CPU 自动选择对应指令序列,并处理重试逻辑(如 stxr 失败时循环重试),对 Java 层完全透明。
Unsafe 不等于裸操作,JVM 加了关键约束
虽然 Unsafe 允许绕过 Java 安全检查访问内存,但它的 CAS 方法仍受 JVM 控制,不是任意指针操作:
- 偏移量(offset)必须来自
objectFieldOffset或staticFieldOffset,确保指向合法字段地址 - JVM 会校验对象是否处于可访问状态(如未被 GC 回收、未被移动),并在 G1/ZGC 等垃圾收集器中插入必要的屏障
- 对 volatile 字段的读写与 CAS 语义协同:CAS 本身具有 volatile 读+写的内存语义(happens-before),JVM 会插入相应内存屏障(如 x86 上
mfence或隐含在lock指令中)
为什么不能直接用 JNI 调用硬件指令?
开发者无法(也不应)在 Java 或 JNI 中手动发射 cmpxchg 指令,原因包括:
- 指令编码、寄存器分配、内存序约束高度依赖 CPU 架构和操作系统 ABI,跨平台不可行
- 缺少 GC 可见性:JVM 需跟踪所有对象引用,裸内存操作可能绕过写屏障,导致并发 GC 出错
- 缺乏优化空间:JIT 编译器无法对 JNI 调用做内联或消除,而
Unsafe方法可被识别为“已知原子操作”,参与逃逸分析、锁消除等优化
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











