longadder通过分段计数(base+cell[])分散cas竞争,避免atomiclong单点争用导致的高自旋失败和cpu空转;适用于写多读少、允许弱一致性的监控统计场景。

因为 LongAdder 通过分段计数显著降低线程竞争,避免了 AtomicLong 在高并发下因 CAS 自旋失败导致的 CPU 浪费和性能陡降。
核心问题:AtomicLong 的瓶颈在哪
AtomicLong 所有线程都争抢同一个变量,靠 CAS 不断重试。当写入线程多(比如每秒上万次)、CPU 核数高(4 核以上)时,CAS 失败率常超 20%,大量线程空转,吞吐量急剧下滑。
LongAdder 怎么解决这个问题
它把“一个计数器”拆成多个独立单元:
- 初始无竞争时,所有累加走 base 变量,轻量高效
- 一旦检测到竞争,就懒加载 cells 数组,每个线程按哈希映射到不同 Cell,各自更新互不干扰
- Cell 内部用 @Contended 避免伪共享,每个单元独占缓存行,减少总线争用
适合什么场景才推荐用
不是所有计数都该换,关键看三点:
- 写操作远多于读操作(例如每秒累加万次,但每分钟只查一次总数)
- 读取不要求瞬时精确值(接受 sum() 返回的是最终一致、可能略滞后的结果)
- 不依赖原子性判断逻辑(比如不用
if (counter.sum() >= 100)做分支控制)
实测收益有多大
在真实高争用环境里效果明显:
- 单线程或低并发(≤4 线程):AtomicInteger 更快,LongAdder 反而慢 5%~10%
- 4 核以上、写占比 >70%、QPS 过万:LongAdder 吞吐量可高出 10~18 倍
- 验证方法:用 Arthas 观察
Unsafe.compareAndSwapLong失败率,持续高于 20% 就是引入 LongAdder 的信号
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











