CAS的底层原理需从硬件、JVM、Java API三层贯通理解:CPU提供cmpxchg等原子指令并加lock前缀保障原子性与可见性;JVM通过Unsafe调用Atomic::cmpxchg桥接硬件;Java层借助AtomicInteger等封装实现,并依赖volatile语义与内存屏障确保正确性。

CAS 的底层原理不是靠背概念就能掌握的,得从硬件、JVM、Java API 三层连起来看。关键不是记住“比较再交换”,而是理解为什么它能原子执行、谁在保证这个原子性、以及 Java 是怎么把硬件能力“翻译”成我们能用的代码的。
先搞懂 CPU 级的原子指令
CAS 不是 Java 发明的,是 CPU 提供的硬保障。比如 x86 架构用 cmpxchg 指令(Compare and Exchange),它在一个 CPU 周期内完成“读值→比对→写入→返回结果”整套动作,中间不会被中断。多核环境下还会自动加 lock 前缀,触发内存屏障,确保其他核心能看到最新值。学的时候可以查 Intel 手册里 cmpxchg 的行为,或者用 JITWatch 工具反编译 HotSpot 生成的汇编,亲眼看到 Java 方法最终落地成哪条机器指令。
再看 JVM 怎么桥接硬件和 Java
Java 不能直接调用 cmpxchg,得靠 JVM 中间层。核心是 Unsafe 类里的 native 方法,比如 compareAndSwapInt。它的 C++ 实现(在 hotspot/src/share/vm/prims/unsafe.cpp)会调用 Atomic::cmpxchg,最终映射到平台相关的汇编封装。你可以翻 HotSpot 源码,重点看 atomic_linux_x86.hpp 或 atomic_windows_x86.hpp 里对 cmpxchg 的封装逻辑——这里就是软硬交界的关键缝合点。
最后落到 Java 编程层怎么用、怎么出问题
别一上来就写 Unsafe。先用 AtomicInteger 等原子类跑个自增循环,再用 JOL(Java Object Layout)工具看对象字段的内存偏移,结合 Unsafe.objectFieldOffset 理解“V(内存地址)”是怎么定位到具体字段的。然后故意构造竞争场景(比如 100 个线程同时 increment),用 VisualVM 观察自旋次数和 CPU 占用变化,再引入 AtomicStampedReference 对比解决 ABA 问题的过程——这样就把“原理→实现→现象→对策”串起来了。
立即学习“Java免费学习笔记(深入)”;
避开几个常见学习误区
- 只背“V/A/B 三参数”伪代码,不验证它到底是不是真原子:建议用 hsdis 工具生成 JIT 编译后的汇编,确认是否真的调用了 cmpxchg
- 认为 CAS = 无锁万能:要亲手测高竞争下自旋带来的 CPU 暴涨,理解为什么 LongAdder 要分段累加
- 忽略内存模型影响:CAS 成功不仅依赖硬件指令,还依赖 happens-before 规则,比如 compareAndSet 后的写操作对其他线程可见,靠的是 volatile 内存语义 + lock 指令的屏障效果
不复杂但容易忽略:CAS 的“原子性”是单指令级的,但它解决并发问题的能力,取决于你如何把它嵌进正确的编程模式里。


















