CAS是解决复合操作原子性缺口的底层机制,通过CPU指令实现“检查-更新”一步完成,典型载体包括AtomicInteger等JUC类,需警惕ABA问题和伪共享。

Java CAS(Compare-And-Swap)不是一种“要读完”的教程,而是一套围绕原子操作构建的底层协作机制。理解它,关键不在通读所有资料,而在建立三层认知:它解决什么问题、怎么在硬件和JVM层面落地、以及在哪些典型工具类中被封装复用。
CAS解决的核心痛点:复合操作的原子性缺口
volatile变量能保证可见性,但像 count++ 这类“读-改-写”三步操作,在多线程下仍会丢失更新——两个线程同时读到 0,各自加1后都写回 1,结果变成 1 而不是 2。CAS正是为填补这个缺口而存在:
- 它把“检查当前值是否等于预期值,是则更新为新值”这一逻辑,交给CPU指令(如 x86 的
cmpxchg)一次性完成 - 整个过程不可中断,天然具备原子性,无需进入内核态加锁
- 失败时返回 false,调用方需自行决定重试(通常用循环),这就是“乐观”策略的体现
CAS在Java中的典型载体:从AtomicInteger到AtomicReference
你不需要直接调用Unsafe,而是通过JUC提供的封装类使用CAS能力:
- AtomicInteger:对 int 字段做原子增减、比较设置,适用于计数器、序列号等场景
- AtomicLongFieldUpdater:不创建额外对象,直接对目标类中 volatile long 字段做CAS,节省内存,适合高频更新的实体字段(如Span时间戳)
- AtomicReferenceArray:将原子能力扩展到数组维度,每个元素可独立更新,适合无锁队列、分段统计等结构
- AtomicReference:支持任意引用类型,配合 compareAndSet 可实现无锁栈、无锁链表等数据结构
必须警惕的两个现实约束:ABA 和伪共享
CAS不是万能银弹,实际使用中容易踩坑:
立即学习“Java免费学习笔记(深入)”;
-
ABA问题:某值从 A → B → A,CAS会误判为“没变”,但实际上中间已被修改。解决方案不是回避CAS,而是引入版本号(如
AtomicStampedReference)或时间戳 - 伪共享(False Sharing):多个原子变量被加载到同一CPU缓存行,即使操作不同变量,也会因缓存行失效引发性能抖动。可通过字节填充(@Contended)或合理布局缓解
学习路径建议:从用到懂,再回到用
不必一上来就啃AQS源码或Unsafe细节:
- 先写一个高并发计数器,对比
volatile int、synchronized和AtomicInteger的表现差异 - 阅读
AtomicInteger.incrementAndGet()源码,看它如何循环调用unsafe.compareAndSwapInt() - 尝试用
AtomicReference实现一个简单的无锁栈,体会CAS失败重试的编程范式 - 再回头理解AQS中
state的CAS更新、ReentrantLock公平/非公平模式下的队列插入逻辑


















