Skip to main content

longAdder

LongAdder 是 Java 8 引入的一个用于高并发环境下进行求和的类

如果有多个线程频繁地对同一个数字进行加减操作(比如计步器、QPS 统计),LongAdder 通常比传统的 AtomicLong 性能更好。


为什么需要 LongAdder?

  • AtomicLong 的瓶颈: AtomicLong 内部使用的是 CAS (Compare-And-Swap) 操作。在高度并发的情况下,大量线程会同时竞争修改同一个变量。因为每次只有一个线程能成功,其他线程会不断自旋重试,这会导致严重的 CPU 资源浪费和性能下降。

LongAdder 的核心原理:分段锁(热点分散)

LongAdder 的设计思路非常聪明:既然大家都争抢同一个变量,那我就把这个变量拆成多个。

  1. 分散热点: LongAdder 内部维护了一个 base 变量和一个 Cell[] 数组。
  2. 无竞争时: 线程直接累加到 base 变量上。
  3. 有竞争时: 不同的线程会被映射到 Cell[] 数组的不同索引位置,各自累加自己的 Cell 值。
  4. 最后求和: 当你需要获取最终的总和时,调用 sum() 方法,它会将 base 和所有 Cell 里的值加起来返回。

比喻: AtomicLong 就像是全班只有一个笔记本,所有人排队等着在那一页纸上写数字; LongAdder 则是给每个人发一张小纸条写,最后老师把所有纸条收上来算个总数。


主要 API

方法说明
add(long x)将当前值增加 x
increment()自增 1
decrement()自减 1
sum()返回当前的总和(注意:这个值不一定是强一致性的
reset()将所有值清零
sumThenReset()获取总和并清零,常用于周期性统计

性能对比与使用场景

1. 性能

  • 低并发: AtomicLongLongAdder 差别不大,甚至 AtomicLong 略快。
  • 高并发: LongAdder 的吞吐量远高于 AtomicLong

2. 如何选择?

  • AtomicLong 如果你需要精确的 CAS 语义(比如 compareAndSet 操作),或者你需要实时保证数值的绝对准确性。
  • LongAdder 如果你的场景是高频写入、低频读取的统计逻辑(如监控数据、网站点击量),且不需要 compareAndSet 这种原子操作。

总结

LongAdder 是通过空间换时间的典型案例。它利用分段增加的方式减少了线程竞争,是处理高并发计数任务的首选利器。不过要记住,它的 sum() 结果是一个“最终一致性”的值,在求和瞬间如果有线程正在写入,结果可能会有微小偏差。

它只适合用来做监控、统计、计数