CAS通过原子指令实现无锁自旋,依赖CPU cmpxchg指令与volatile语义保障可见性与顺序性;AtomicInteger基于此在低竞争下性能优于锁,高竞争时LongAdder分段累加更优。

CAS(Compare-And-Swap)通过原子指令实现无锁自旋,避免线程阻塞和上下文切换开销,是构建高性能并发计数器的核心机制。Java 中 AtomicInteger 等类正是基于此原理,在低竞争场景下获得远超 synchronized 或 ReentrantLock 的吞吐量。
底层依赖 CPU 原子指令与 volatile 语义
CAS 操作由 JVM 映射为一条 CPU 级原子指令(如 x86 的 cmpxchg),确保“读-比-写”三步不可分割。同时,被操作的变量必须声明为 volatile,保证每次读取都从主内存获取最新值,写入立即刷新到主内存,避免线程本地缓存导致的可见性问题。
- Java 8+ 中
Unsafe.compareAndSetInt是 CAS 的实际入口,由 JIT 编译器优化为单条硬件指令 -
volatile不提供原子性,但为 CAS 提供必要的内存屏障(LoadLoad、StoreStore 等),保障操作顺序与可见性 - 没有锁对象头开销、无 Monitor 争用、不触发线程挂起/唤醒,天然规避了锁抢占损耗
自旋重试:用 CPU 时间换调度开销
当 CAS 失败(预期值与当前值不一致),线程不阻塞,而是立即重试——即“自旋”。这在竞争不激烈时非常高效;但高竞争下可能造成 CPU 空转,需权衡。
- 典型实现如
AtomicInteger.incrementAndGet()内部循环调用compareAndSet,直到成功 - 可结合指数退避(如 Thread.onSpinWait()、短暂 yield 或纳秒级 park)缓解过度自旋,JDK 9+ 已在部分原子类中引入轻量级退避逻辑
- 注意:自旋不是“忙等万能解”,若预计更新频率极高(如每微秒多次),应考虑分段计数(如 LongAdder)来分散热点
避免 ABA 问题:必要时引入版本戳
CAS 只校验值是否相等,无法区分“值未变”和“值先变后又变回”的情况(ABA)。对计数器这类单调递增场景影响不大,但若扩展为栈、队列等结构,则需防范。
立即学习“Java免费学习笔记(深入)”;
- 计数器本身无需处理 ABA:+1 操作不依赖中间状态,只要最终值正确即可
- 若需更复杂状态管理(如带标记的引用),可用
AtomicStampedReference或AtomicMarkableReference,将版本号或标记位与数据捆绑 CAS - Java 17+ 的
VarHandle提供更灵活的 CAS 控制,支持带掩码的原子更新,进一步降低误判概率
进阶优化:从 AtomicInteger 到 LongAdder
单点 CAS 在高并发写场景下仍会成为瓶颈(大量线程争抢同一内存地址)。LongAdder 采用“分段累加 + 最终合并”策略,显著提升吞吐量。
- 内部维护一个 base 值 + 多个 Cell 数组,线程哈希定位到不同 Cell 执行 CAS 更新,减少冲突
- 读取时需遍历所有 Cell 并加总,牺牲一点读性能换取写性能大幅提升
- 适用于“写多读少”的统计类场景(如接口 QPS 计数),而
AtomicInteger更适合需要强实时读取的场景



















