AtomicInteger.compareAndSet()是基于CAS指令的无锁原子更新方法,它原子性比较并设置值,失败不阻塞线程,适用于自增、状态机等场景,需注意ABA问题和循环重试控制。

在 Java 中,AtomicInteger.compareAndSet() 是实现无锁(lock-free)线程安全更新的核心方法之一。它利用 CPU 的 CAS(Compare-And-Swap)指令,避免使用 synchronized 或显式锁,从而减少线程阻塞、提升并发性能。
理解 compareAndSet() 的工作原理
compareAndSet(expectedValue, newValue) 原子性地检查当前值是否等于 expectedValue;如果是,则将值设为 newValue,并返回 true;否则不修改,返回 false。整个过程不可中断,由底层硬件保证原子性。
关键点:
- 它不是“乐观锁”,而是无锁(lock-free)原语——不依赖互斥锁,也不阻塞线程
- 失败时不会挂起线程,调用方需自行决定重试或放弃
- 适用于低竞争场景效果显著;高竞争下可能因反复重试带来一定开销
典型用法:自增、条件更新与计数器
最常见的是实现线程安全的自增(如替代 i++),或带条件的状态变更(如状态机流转)。
示例:线程安全的自增
AtomicInteger counter = new AtomicInteger(0);
// 安全地执行 counter++
int current;
int next;
do {
current = counter.get();
next = current + 1;
} while (!counter.compareAndSet(current, next));
更简洁的等价写法(JDK 已封装):counter.incrementAndGet(); —— 其内部正是基于 compareAndSet 循环实现。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
实现状态机或有约束的更新
当变量代表某种状态(如订单状态:INIT → PROCESSING → DONE),且只允许按规则推进时,compareAndSet 天然适合。
示例:仅允许从 INIT(0) 更新为 PROCESSING(1)
AtomicInteger status = new AtomicInteger(0); // INIT
<p>boolean started = status.compareAndSet(0, 1); // 只有初始是 0 才能设为 1
if (started) {
// 成功启动,继续处理...
} else {
// 可能已被其他线程启动,拒绝重复操作
}
</p>
这种模式避免了加锁判断再修改的“检查-执行”竞态问题(check-then-act race)。
注意事项与常见陷阱
使用 compareAndSet 时需注意以下几点:
-
ABA 问题存在但通常可忽略:值从 A→B→A,CAS 会成功,但中间可能已发生语义变化。多数计数/状态场景不影响正确性;若敏感(如栈顶节点复用),可用
AtomicStampedReference -
循环重试要有退出机制:死循环可能耗尽 CPU,尤其在高竞争下。可加入短暂让出(
Thread.yield())或限制最大尝试次数 - 不要假设一次调用就能成功:必须根据返回值做逻辑分支,不能忽略 false 返回
- 与 volatile 语义不同:它保证读-改-写原子性,而 volatile 仅保证可见性和禁止重排序,不保证复合操作原子性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










