LongAdder 不能直接替代 AtomicInteger,因类型不同且语义不一致;仅适用于写多读少、无需瞬时精确值的统计场景,如 API 调用量统计,且需接受最终一致性读取模型。

LongAdder 不能直接替代 AtomicInteger,因为两者类型不同(long vs int),且设计目标和语义不一致。若需用 LongAdder 替代 AtomicInteger,必须先确认业务允许将计数器升级为 long 类型,并接受其“最终一致性”读取模型——这是安全替换的前提。
明确适用场景:写多、读少、不要精确瞬时值
LongAdder 只适合以下情况:
- 计数用途是统计类指标(如 API 调用量、错误次数、日志采样数),而非控制逻辑分支
- 读取频次远低于写入(例如每秒写入万次,但每分钟只读一次汇总)
- 代码中没有基于计数值做条件判断,比如
if (counter.get() >= 100)或counter.compareAndSet(0, 1) - 不依赖
getAndIncrement()这类返回旧值的操作
替换操作要点:初始化、累加、读取要对应
用法上看似简单,但关键细节容易出错:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 初始化:直接
new LongAdder(),无需指定初始值(它默认为 0) - 累加:用
increment()或add(1)替代incrementAndGet();注意它不返回当前值 - 读取总量:调用
sum(),不是get();该方法遍历内部 cells 数组并累加,结果可能略滞后于最新写入 - 重置计数:用
reset(),但它不是原子操作,若读写并发,sum() 可能在 reset 中途返回部分清零的结果
避开典型误用陷阱
这些写法看着像能替换,实际会引入隐蔽问题:
立即学习“Java免费学习笔记(深入)”;
- 把
if (counter.get() > threshold)改成if (counter.sum() > threshold)—— sum() 非强一致,可能漏判或误判 - 在定时任务里频繁调用
sum()(如每毫秒一次)—— 它是 O(n) 操作,n 是 cells 数组长度,高并发下数组可能较大,拖慢读取 - 低并发环境(≤4 线程)盲目替换 —— 此时 LongAdder 因 probe 计算、数组跳转等额外开销,反而比 AtomicInteger 慢 5%~10%
- 期望用它实现“仅当小于 N 时才加 1”这类逻辑 —— LongAdder 不提供 compareAndSet,必须退回 AtomicInteger 或加锁
性能收益看真实竞争程度
吞吐提升不是恒定的,取决于实际线程争用强度:
- 单线程或轻度并发:AtomicInteger 更快
- 4 核以上、写操作占比超 70%、QPS 过万时,LongAdder 优势明显,实测可快 10~18 倍
- 验证是否真有收益:用 Arthas 观察
Unsafe.compareAndSwapLong的失败率,若失败率持续高于 20%,说明 CAS 竞争已成瓶颈,LongAdder 才值得引入

















