LongAdder 的 sum() 方法返回近似值而非原子快照,因其遍历 cells 时无锁且不阻塞写入,导致结果仅为调用时刻可见部分的累加和;适用于监控统计等弱一致性场景,不适用于库存扣减等强一致需求。

LongAdder 的 sum() 方法在并发环境下返回的是一个近似值,不具备强一致性,这是它设计上的明确取舍,而非缺陷。
为什么 sum() 不是原子快照?
sum() 的执行过程是:先读取 base 值,再遍历 cells 数组中所有非 null 的 Cell,并累加它们的 value。这个过程不加锁、不阻塞写入——也就是说,其他线程可能正在:
- 往某个已存在的 Cell 中执行 add(),更新其值;
- 触发扩容,新建 Cell 并插入数组;
- 甚至刚完成 CAS 更新,但该新值尚未被当前 sum() 遍历到。
因此,sum() 返回的结果只是调用时刻“可见部分”的累加和,无法反映某一精确时间点的全局状态。
近似值在哪些场景下可接受?
它的弱一致性恰恰匹配了多数监控与统计类需求的真实语义:
立即学习“Java免费学习笔记(深入)”;
- 每秒请求数(QPS)指标:允许毫秒级延迟或少量偏差,重点是趋势和量级;
- 错误计数、日志打点频次:只要最终收敛、不丢数据,中间瞬时值无需精确;
- 限流器中的粗粒度计数器(如分钟级阈值判断):只要周期内总量可控,单次读取误差不影响策略有效性。
这类场景关注的是最终一致性和高吞吐写入能力,而非实时精确快照。
什么情况下不能用 sum()?
一旦业务逻辑依赖严格顺序或瞬时精确值,sum() 就不再适用:
- 库存扣减:必须确保“读-判-扣”原子性,否则超卖风险极高;
- 分布式幂等令牌生成:需要唯一且不可重复的递增值;
- 金融类余额变更:任何中间态误差都可能导致账务不平。
这些场景应回归 AtomicInteger、AtomicLong 或数据库行锁等强一致机制。
sumThenReset() 也不能替代强一致
尽管 sumThenReset() 把求和与清零封装为一次调用,但它仍不保证对其他线程的排他性:
- 它只对当前线程看到的 cells 状态求和并重置;
- 若另一线程正往某个已被 reset 的 Cell 写入,该增量不会丢失,但也不会计入本次 sumThenReset() 的结果中;
- 它不是事务性操作,也不提供 happens-before 保障来约束其他线程行为。
所以它适合做周期性汇总+清零(如每分钟采集指标),但不能用于需严格因果关系的业务逻辑。


















