longadder比atomiclong快在高并发下减少cas争抢:它通过分段cell数组分散更新压力,避免atomiclong单点自旋风暴;适用于写多读少、弱一致场景,如监控计数,不适用于强一致序列号生成。

LongAdder 是 Java 8 引入的高性能原子计数器,专为高并发、多线程频繁更新场景设计,能显著缓解 AtomicLong 在争用激烈时的性能瓶颈。
为什么 AtomicLong 在高并发下会变慢?
AtomicLong 依赖 CAS(Compare-And-Swap)操作实现线程安全,所有线程都竞争同一个 volatile 变量。当多个线程同时调用 incrementAndGet(),大量 CAS 失败导致自旋重试,CPU 开销大、吞吐下降。
LongAdder 则采用“分段累加 + 最终合并”策略:内部维护多个 Cell(类似分片),线程优先尝试更新自己的 Cell;冲突时再尝试其他 Cell 或 base 值,大幅降低竞争。
LongAdder 的基本用法和关键 API
使用方式比 AtomicLong 更简单——它不提供 getAndIncrement 等复合操作,核心是「只增不查」的累加模型:
- increment():无返回值,线程安全地加 1
- add(long x):无返回值,加指定值
- sum():获取当前总和(非实时强一致,但最终一致)
- longValue():等价于 sum(),方便用于泛型或函数式接口
- reset():清零(注意:不是原子性重置,适合周期性统计场景)
示例:
LongAdder counter = new LongAdder();counter.increment();
counter.add(5);
long total = counter.sum(); // 6
什么时候该用 LongAdder 而不是 AtomicLong?
适用场景有明确特征:
- 写多读少:计数器被高频更新(如 QPS 统计、请求量累计),但读取不频繁(比如每秒汇总一次)
- 不要求实时精确值:sum() 结果反映的是某时刻的近似总和,不适合做“CAS 条件判断”的依据(例如不能替代 if (get() == 0) doSomething())
- 线程数较多且更新集中:实测在 4+ 线程并发 increment 时,LongAdder 性能通常比 AtomicLong 高 2–10 倍(取决于 CPU 核心数和争用强度)
反例:需要原子性读-改-写(如实现限流器令牌桶的 tryAcquire),仍应选 AtomicLong 或更合适的工具(如 Striped64 衍生类、Semaphore)。
注意事项和常见误区
- sum() 不是锁同步操作,但也不是完全无开销:它需遍历所有 Cell 并累加,Cell 数量随争用动态扩容,极端情况下可能影响读性能
- 不能序列化:LongAdder 实现了 Serializable,但反序列化后状态丢失(sum() 返回 0),生产环境避免直接存/取对象
- reset() 不保证绝对原子性:先清 base 再逐个清 Cell,中间可能有新更新写入,适合统计周期结束后的粗粒度重置
- 内存占用略高:每个 Cell 是独立对象,争用激烈时 Cell 数可达 CPU 核心数级别,不过对现代 JVM 影响有限
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











