longadder专为高并发累加设计,通过“base+cell数组”分散写操作降低cas冲突,适用于写多读少、接受最终一致性的统计场景,不支持强一致读写或原子条件更新。

LongAdder 专为高并发累加场景设计,它不追求单次操作的强一致性,而是用“分散写 + 合并读”换来了远高于 AtomicLong 的吞吐量。核心思路是把一个热点变量拆成 base 值加多个 Cell,让线程尽量写不同位置,大幅降低 CAS 冲突。
什么时候该用 LongAdder 而不是 AtomicLong
判断依据不是“并发量大”,而是“写操作密集、读操作相对稀疏、且能接受最终一致性”:
- 统计类场景:QPS 计数器、请求总数、错误次数、日志采样计数等;
- 写远多于读:比如每毫秒数百次 increment,但每秒只调用一两次 sum();
- 不要求实时精确值:sum() 返回的是当前所有 Cell 和 base 的快照和,期间若有新写入,不会体现在本次结果中;
- AtomicLong 更适合需要强一致读写的场景,比如序列号生成、库存扣减(需配合业务校验)等。
基本用法与关键 API
LongAdder 使用极简,初始化后直接调用写方法,读取时再聚合:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 写操作:`increment()`(+1)、`add(long x)`(+x),无返回值,内部自动选择 base 或 Cell 更新;
- 读操作:`sum()` 获取当前总和,非阻塞但非强一致;`longValue()` 等价于 `sum()`;
- 重置计数:`reset()` 清空所有 Cell 并将 base 设为 0,注意这不保证原子性(中间可能有写入);
- 不提供 compareAndSet、getAndAdd 等原子读-改-写接口——它不是通用原子变量,而是专用累加器。
底层怎么做到“分散竞争”
LongAdder 内部结构分两层:
- base 字段:一个 volatile long,低竞争时所有线程都尝试更新它;
- Cell 数组:当 base 更新失败(CAS 失败)达到一定次数,就初始化 Cell 数组;每个线程通过自身 threadLocal 的 probe 值哈希到某个 Cell 槽位,只对该槽位做 CAS;
- Cell 是懒加载、按需扩容的,避免内存浪费;数组长度总是 2 的幂,哈希用位运算(probe & (cells.length - 1))提升效率;
- sum() 时遍历整个 Cell 数组,加上 base,得到最终值。
使用注意事项
避开常见误用,才能真正发挥性能优势:
- 别把它当 AtomicLong 替代品:不支持 getAndIncrement、不提供原子条件更新,强行模拟会破坏设计初衷;
- sum() 不是锁,也不阻塞写入:高并发下连续两次 sum() 可能返回相同值,也可能差很多,取决于中间写入节奏;
- 内存开销略高:一个 LongAdder 默认至少占用几个对象(base + cells 数组 + 若干 Cell 实例),比 AtomicLong 的单个 long 大;
- 初始化时机透明:首次竞争失败才建 Cell,所以压测前最好预热(如调用一次 increment)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










