LongAdder通过分段累加机制缓解高并发瓶颈,将全局计数器拆为base字段和Cell数组,线程优先本地更新避免CAS竞争;AtomicLong因所有线程争抢同一内存地址导致大量自旋失败,性能低5–10倍。

LongAdder 通过分段累加(striped counter)机制,把一个全局计数器拆成多个 Cell,让线程尽量在不同 Cell 上做局部更新,避免 CAS 竞争,从而显著缓解高并发下的原子计数瓶颈。
为什么 AtomicLong 在高并发下会成为瓶颈
AtomicLong 底层依赖 Unsafe.compareAndSwapLong,所有线程都争抢同一个内存地址。当线程数多、更新频繁时,大量 CAS 失败导致自旋重试,CPU 消耗高、吞吐下降。实测中,100+ 线程同时 increment,AtomicLong 的性能可能比 LongAdder 低 5–10 倍。
LongAdder 是怎么分段的
它内部维护一个 base 字段 + 一个 Cell 数组(类似哈希表):
- 初始只用 base,轻量无竞争
- 发生竞争(CAS base 失败)后,尝试初始化 cells 数组,并用线程的 probe 值(类似 ThreadLocalRandom 的 threadLocalProbe)映射到某个 cell 槽位
- 后续同一线程优先复用同一 cell,减少跨槽争用
- cells 数组支持动态扩容(类似 ConcurrentHashMap),但扩容条件较保守,避免过度开销
什么时候该用 LongAdder 而不是 AtomicLong
适用场景有明确特征:
- 计数为主、读少写多(如 QPS 统计、请求总量、错误计数)
- 不要求实时强一致性(sum() 是最终一致,非即时快照)
- 不依赖 compareAndSet 或 getAndIncrement 这类原子语义
- 能接受少量内存开销(每个 cell 占 24 字节,加上数组本身)
反例:需要精确控制递增顺序、做条件更新(如“只有小于 100 才加”)、或作为同步状态变量,仍应选 AtomicLong 或更高级工具(如 StampedLock 配合普通 long)。
使用时的关键注意事项
LongAdder 不是“即插即用”的黑盒,需注意几个细节:
- sum() 不是原子快照:遍历 cells 过程中其他线程可能正在修改,结果反映的是近似和;如需严格一致,应配合外部同步(但通常没必要)
- reset() 不是原子清零:它先重置 cells 各元素,再设 base=0,中间可能被其他线程插入更新
- 不支持 decrement(减操作):只能 add(-n),不能像 AtomicLong 那样直接 decrementAndGet
- 避免长期空闲后突然高并发:cells 可能未初始化,首波竞争会触发初始化+扩容,带来短暂延迟毛刺
不复杂但容易忽略:多数监控类计数场景,LongAdder 就是更优解;关键在理解它“为吞吐妥协一致性”的设计取舍,而不是把它当成 AtomicLong 的无缝替代。










