CAS是Java并发编程的底层原子机制,本质为CPU指令cmpxchg,通过“比较—判断—更新”三要素(内存地址V、预期值A、新值B)实现非阻塞同步,其原子性支撑了AtomicInteger自旋重试、ConcurrentHashMap与AQS等JUC组件的核心逻辑。

CAS 是 Java 并发编程的核心底层机制,不是靠死记硬背能掌握的,关键在于理解“比较—判断—更新”这一原子动作如何替代锁、为什么能非阻塞、以及它在真实类库中怎么被封装和使用。
抓住 CAS 的三个核心要素
CAS 操作必须同时满足三个条件才成立:内存地址(V)、预期旧值(A)、目标新值(B)。它的本质是一条 CPU 硬件指令(如 x86 的 cmpxchg),由 JVM 通过 Unsafe 类调用 native 方法实现。学的时候要反复对照这个公式:
if (V == A) { V = B; return true; } else { return false; }
注意:这个判断+赋值是原子的,中间不会被打断——这是它能用于并发安全的基础。
从 AtomicInteger 入手看真实调用链
不要只看概念,直接打开 AtomicInteger.getAndIncrement() 源码:
→ 调用 Unsafe.getAndAddInt(this, valueOffset, 1)
→ 进入一个 do-while 循环,不断读取当前值(getIntVolatile)作为预期值 A
→ 尝试用 CAS 更新:如果成功就跳出,失败就重试
这个“自旋重试”模式就是 CAS 最典型的使用方式,也是理解乐观锁思想的关键入口。
必须搞清三大经典问题及其应对逻辑
面试和实战中高频出现,不能只背结论:
- ABA 问题:值从 A→B→A,CAS 误判为未变。解决方案不是“不用 CAS”,而是加版本号——AtomicStampedReference 就是把“值 + 时间戳/版本”打包成一个 pair 来比
- 自旋开销大:高竞争下线程反复重试浪费 CPU。JDK 并没有无限自旋,比如 LongAdder 在竞争激烈时会退化为分段累加(cell 数组),减少单点冲突
- 只能保证单变量原子性:i++ 和 j++ 无法用一个 CAS 同时完成。这时要么用锁,要么用 AtomicReference 包装对象,或借助 StampedLock 等更高级同步器
结合 JUC 组件看 CAS 的实际落点
脱离源码谈 CAS 是空谈。重点跟踪两个典型场景:
- ConcurrentHashMap(JDK 8+):put 操作先尝试 CAS 更新 baseCount;失败后扩容或写入 CounterCell 数组,仍依赖 CAS 更新对应 cell;只有在数组初始化或扩容冲突时,才退到 synchronized 保护
- AQS(AbstractQueuedSynchronizer):state 字段的修改全部基于 Unsafe.compareAndSwapInt,ReentrantLock 加锁、释放、tryAcquire 都绕不开它——CAS 是 AQS 实现非阻塞同步的基石


















