CAS是Java实现乐观锁的核心机制,依赖CPU硬件指令(如x86的cmpxchg)保障“比较-交换”原子性,通过Unsafe类封装为compareAndSet方法,广泛应用于AtomicInteger等原子类及JUC组件,但存在ABA问题和单变量限制。

CAS 是 Java 中实现乐观锁最直接、最常用的底层机制,它不依赖传统锁,而是靠硬件指令保证原子性,在低冲突场景下性能优势明显。
核心就是 compareAndSet 方法
Java 并不让你直接调用 CPU 的 CAS 指令,而是通过 java.util.concurrent.atomic 包下的原子类封装好,最常用的是:
- AtomicInteger:用于整数计数、状态标记等
- AtomicLong:大数值场景,如高并发 ID 生成
- AtomicBoolean:开关控制、初始化标志位
- AtomicReference:支持任意对象的原子更新(配合自定义状态类很实用)
所有这些类都提供 compareAndSet(expected, update) 方法——传入“我读到的旧值”和“我想设的新值”,成功返回 true,失败返回 false,由你决定是否重试。
典型用法:自旋重试实现无锁更新
比如一个线程安全的计数器,不用 synchronized,靠循环 + CAS 实现:
public void increment() {
while (true) {
int current = count.get();
int next = current + 1;
if (count.compareAndSet(current, next)) {
break; // 成功了,退出
}
// 失败说明被别人抢先改了,重新读、再算、再试
}
}
这就是“CAS 自旋”:失败不阻塞,立刻重来。适用于冲突少、操作快的场景;若写竞争激烈,可能空转耗 CPU,此时需评估是否换悲观锁。
实际业务中常见应用模式
CAS 不只是加加减减,它支撑着很多 JUC 组件的底层逻辑:
- 状态机控制:如订单从“待支付”→“已支付”,用 AtomicReference 存状态对象,只允许从特定旧值更新为新值
- 无锁队列/栈:ConcurrentLinkedQueue 的入队出队都基于 CAS 更新 head/tail 指针
- 轻量级锁升级判断:synchronized 在偏向锁撤销或轻量级锁膨胀前,也会用 CAS 尝试修改对象头中的锁标志位
- 配置热更新:用 AtomicReference 缓存最新配置对象,更新时 CAS 替换引用,读取方始终拿到一致快照
要注意的几个关键点
CAS 看似简单,但落地时容易踩坑:
-
ABA 问题:值从 A→B→A,CAS 会误判为“没变过”。可用
AtomicStampedReference加版本戳解决 - 只能保证单变量原子性:两个字段一起更新?CAS 无法一步搞定,得用 AtomicReference 封装整个对象,或改用锁
- 自旋不是万能的:长时间重试会浪费 CPU,必要时可结合 Thread.yield() 或有限次数后降级为 synchronized
- volatile 是搭档:所有原子类内部字段都用 volatile 修饰,确保每次读取都是最新值,这是 CAS 正确工作的前提
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











