atomicinteger 能实现无锁计数,因其基于 volatile 保证可见性与有序性,并通过 unsafe 调用 cpu 级 cas 指令(如 cmpxchg)原子更新 value,成功则提交,失败则由调用方决定重试。

Java 中用 AtomicInteger 结合 CAS 实现无锁高并发计数器,核心是利用其底层基于 CPU 指令(如 cmpxchg)的原子更新能力,避免 synchronized 或 Lock 带来的线程阻塞和上下文切换开销。
为什么 AtomicInteger 能实现无锁计数
AtomicInteger 内部持有一个 volatile int value,所有读写都遵循 volatile 语义(可见性 + 禁止重排序),而关键的更新操作(如 incrementAndGet()、compareAndSet())通过 Unsafe 类调用硬件级 CAS 指令完成。CAS 成功则更新并返回 true;失败则说明值已被其他线程修改,通常会重试(由调用方控制,比如 getAndIncrement() 内部已封装自旋逻辑)。
常用无锁计数操作及写法
以下是最典型的几种安全计数方式,全部线程安全且无显式锁:
-
自增计数:直接用
counter.incrementAndGet()—— 原子加 1 并返回新值;或counter.getAndIncrement()—— 返回旧值再加 1 -
条件更新(带业务逻辑):例如“仅当当前值为 5 时才加 1”,用
counter.compareAndSet(5, 6);若失败可配合 while 循环重试(注意避免死循环,必要时加简单退避) -
批量累加(JDK 8+):对高竞争场景,
LongAdder/DoubleAdder比AtomicInteger更高效(采用分段累加+最终汇总),但若只需简单计数且竞争不极端,AtomicInteger更轻量、语义更清晰
一个完整示例:模拟高并发请求计数
下面是一个启动 100 个线程,每个执行 1000 次自增的典型测试:
AtomicInteger counter = new AtomicInteger(0);
List<thread> threads = new ArrayList();
for (int i = 0; i {
for (int j = 0; j {
try { t.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
});
System.out.println("Final count: " + counter.get()); // 总是输出 100000
</thread>
该代码无需任何同步块,结果严格准确,且性能远高于使用 synchronized(this) 或 ReentrantLock 的等效实现(尤其在线程数多、操作频繁时)。
注意事项与边界情况
CAS 机制虽高效,但需留意几点实际约束:
-
ABA 问题存在但对计数器不构成影响:计数场景只关心数值变化,不依赖中间状态,即使某值从 A→B→A,
incrementAndGet仍能正确递增,无需额外处理 -
不能替代复合操作的原子性:比如“先读再判断再写”这类多步逻辑,
AtomicInteger本身不保证整体原子性,必须用compareAndSet手动建模或改用StampedLock等更高级工具 -
过度自旋可能浪费 CPU:在极高争用下(如上千线程同时疯狂 CAS 同一变量),失败重试可能密集占用 CPU,此时应评估是否改用
LongAdder或引入限流/分片策略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











