LongAdder 和 AtomicLong 有什么区别?为什么高并发计数不一定选 AtomicLong?
下面是一段教学用的模拟面试。
🧑💻 面试官:LongAdder 为什么在高并发统计里常比 AtomicLong 快?
🙋♂️ 我:它把更新分散到多个单元,减少竞争。
🧑💻 面试官:那剩余库存也换成 LongAdder,吞吐不就上去了吗?
🙋♂️ 我:库存扣减需要更严格的判断,不能直接这么换。
🧑💻 面试官:具体差在哪里?sum 读到的值,是某个时刻的原子快照吗?
先分清「累计统计」和「根据当前值做决定」。LongAdder 擅长分散更新,不负责替你完成原子的库存判断。
面试速答(60 秒版)
AtomicLong 围绕一个值提供原子操作,可以做读取、更新和 compareAndSet。多个线程频繁修改同一个值时,会集中竞争这一个位置。
LongAdder 在竞争较大时,会把更新分散到多个单元,读取时再把它们加起来。所以它适合请求次数等高并发累计统计,但通常需要更多空间。
关键区别是,LongAdder 的 sum 在并发更新时,不保证是某一时刻的原子快照。它也没有“先判断剩余数量,再原子扣减”的同等操作。
因此,统计吞吐可以评估 LongAdder;库存、余额、唯一序号或精确状态转换,则要选择满足原子语义的方案。即使用 AtomicLong,也不能把普通的先读后写当成一个原子操作。

图:AtomicLong 维护单个原子值,LongAdder 把更新分散到多个位置;这不是说它们的所有操作都采用同一种 CAS 循环。
知识点详解:吞吐更高,为什么不等于可以替代?
一个值被大家修改,竞争在哪里?
假设很多工作线程都要给请求计数加一。AtomicLong 的更新围绕一个共享值进行,并发冲突会让操作重试。
这里的问题不是“线程没有独立变量”,而是所有更新最终都要争用同一处共享状态。竞争越强,重试和缓存一致性成本越明显。
LongAdder 可以根据竞争情况增加计数单元,让不同线程的更新分散。统计时再把基础值和这些单元相加。它不是一开始就给每个线程永久分配一个专属计数器,也不保证总是比 AtomicLong 快。
低竞争时二者特征可能相近,高竞争累计统计才是它的典型用处,见 LongAdder API。
sum 为什么不能当成库存的当前值?
读取多个单元需要一个过程。读第一个单元后,其他线程可能继续修改第二个,也可能再修改已经读过的第一个。
最后的总和不保证对应某个统一瞬间。因此,并发统计可以接受这种非原子观察时,LongAdder 很方便;但需要精确判断“现在是否还有一个名额”,它就不能直接提供这个保证。
没有并发更新时,sum 可以得到准确结果。不要把“不保证原子快照”夸张成“它总是随机丢计数”。

图:逐个求和,不是同一瞬间快照。
AtomicLong 也不是写两行就自动正确
假设先读取库存,发现大于零,再调用 decrementAndGet。这是两个独立操作。两个线程都可能先看到还有一个库存,然后都去扣减。
要实现条件扣减,需要让判断和修改成为同一个受保护的状态转换,例如使用正确的 CAS 循环或锁。分布式库存还涉及数据库事务、幂等和跨实例协调,单进程 AtomicLong 并不能包办。
AtomicLong 提供的操作语义可以核对 官方 API。

图:先读后扣,不是一个原子操作。
reset 为什么也要小心?
LongAdder 的 reset 和 sumThenReset 不适合在持续并发更新中,被当作精确的统计窗口切分。
重置多个单元时,更新可能交错发生,不能保证“这一秒的全部更新都在前一个结果里,下一秒的全部更新都在后一个结果里”。
如果只是周期性近似观察,可以按需求评估;如果是计费或精确结算,应采用能证明窗口归属的设计,而不是因为方法名有 Reset 就认为边界准确。
| 需求 | 首先关心 |
|---|---|
| 高并发请求累计 | 更新吞吐与可接受的观察误差 |
| 条件扣库存 | 判断和扣减是否原子 |
| 唯一递增序号 | 每次操作是否返回唯一结果 |
| 精确窗口结算 | 每条事件的窗口归属 |
本题是 Java 原子类语义比较,不提供伪造的 TypeScript/Python 同名实现。
面试官继续追问
LongAdder 的 add 本身会丢更新吗?
正确使用下,更新会累积到内部计数中。需要区分“累计更新正确”与“并发读取形成原子快照”,它们不是同一项保证。
为什么会占更多空间?
它可能维护多个单元及相关布局,用空间换竞争降低。大量计数器都放在小对象中时,也要评估总内存开销。
只做一个简单计数,该选哪个?
先选满足语义且足够简单的方案。确认存在高竞争瓶颈,再在相同线程数和更新/读取比例下基准测试,不根据工具名判断性能。
面试速记卡
- AtomicLong:单值原子操作,支持 CAS。
- LongAdder:分散更新,适合高并发累计统计。
- sum:并发更新时不保证原子快照。
- 条件修改:先读后写仍然可能竞争。
- reset:不自动形成精确统计窗口。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →