LongAdder通过分段计数、@Contended缓存行填充和线程哈希映射分散写竞争,避免伪共享;sum()提供最终一致性,以弱一致性换取高吞吐,适用于监控统计等场景。

LongAdder 的 cells 数组不是为“击碎”缓存行竞争而设计的,而是通过**分段计数 + 缓存行填充(@Contended)+ 线程哈希映射**,把高并发下的写竞争从单点(base)分散到多个独立内存位置,从而大幅降低 CPU 缓存行伪共享(false sharing)和总线争用,最终提升吞吐量。
cells 数组如何避开单点缓存行热点
普通 AtomicLong 的 increment() 全部挤在同一个 long 字段上,每次 CAS 都要 invalid 所有 CPU 核心里该缓存行的副本,造成严重争用。LongAdder 则:
- 先尝试无锁更新 base 字段(低并发时足够快)
- 一旦发生 CAS 失败(说明有竞争),就初始化 cells 数组,并基于当前线程的 probe 值(类似 ThreadLocalRandom 的 threadLocalProbe)计算 hash 槽位
- 每个 cell 是一个独立的 volatile long,且被 @Contended 注解保护 —— JVM 会自动在其前后填充 128 字节,确保它独占至少一个缓存行(通常 64 字节),彻底隔离伪共享
- 不同线程大概率落到不同 cell 上,写操作不再互相干扰
probe 值不是随机数,而是线程本地可变状态
Thread.currentThread().getThreadLocalRandomProbe() 返回的 probe 值由 JVM 维护,首次调用时生成并绑定到线程,后续复用。它不随每次操作变化,但足够分散;若某 cell 冲突严重(多次 CAS 失败),LongAdder 会触发 cell 数组扩容(类似 HashMap),并重新哈希分配,进一步摊薄压力。
sum() 不是实时强一致,但代价极小
sum() 遍历所有 cell 并加上 base,是最终一致性(eventual consistency)。它不加锁、不阻塞,只是读取 —— 即使遍历时某个 cell 正被其他线程更新,也只是多算或少算一次增量,对统计类场景完全可接受。这正是它比 AtomicLong 在高并发累加中快几倍到几十倍的关键:用弱一致性换极高写吞吐。
立即学习“Java免费学习笔记(深入)”;
别滥用:适用场景很明确
LongAdder 不是万能替代品:
- ✅ 适合:高频 increment/decrement、监控计数器、采样统计、限流令牌桶计数等“只写多、读少、允许短暂不精确”的场景
- ❌ 不适合:需要实时精确值的逻辑(如余额扣减)、依赖 compareAndSet 的原子条件更新、或必须严格顺序的计数
- ⚠️ 注意:cells 数组大小是 2 的幂,扩容成本存在,极端情况下(比如 probe 全哈希到同一槽)仍可能退化为 base 竞争,但概率极低



















