longadder的reset()方法不保证并发安全,仅在无并发写入时有效;其清零过程无锁、非原子,可能导致状态不一致;推荐用sumthenreset()替代,适用于qps采样等最终一致性场景。

LongAdder 的 reset() 方法本身不保证并发安全,直接调用它时若存在其他线程正在执行 add()、increment() 等写操作,会导致计数器状态不一致——比如部分 Cell 被清零而另一些未被处理,或 base 已重置但某个线程刚完成对 Cell 的 CAS 更新,最终 sum() 返回值既非旧值也非 0。
reset 的设计前提:无并发写入
官方注释明确指出:“only effective if there are no concurrent updates”。它的逻辑是先置 base = 0L,再遍历 cells 数组将每个 Cell.value 设为 0。这个过程没有加锁、不使用 CAS、也不校验中间状态,属于典型的“尽力而为”式清理。
- 如果某线程在
reset()执行中途调用add(x),可能写入已被清零的Cell,也可能因cells正在被遍历而错过更新 - 若
cells正处于扩容中(cellsBusy == 1),reset()会跳过该数组,仅清空base,导致后续sum()结果严重偏低 - 多个线程同时调用
reset()不会产生异常,但彼此干扰,无法确保最终归零
替代方案:用 sumThenReset 避免读写竞争
sumThenReset() 是更实用的选择——它先原子性地计算当前总和,再尝试重置。虽然重置阶段仍不防并发写入,但它把“读取”和“重置”两个动作做了逻辑绑定,适用于采样类场景:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 适合做 QPS 统计:每秒调用一次
sumThenReset(),拿到该秒增量后清零,下秒重新累加 - 返回值是“快照和”,不受 reset 后新写入影响;即使重置未完全生效,也不影响本次采样结果的完整性
- 注意:它不保证重置绝对完成,高并发下仍可能残留少量未清单元,但误差可控且单向(只少不多)
真正需要强一致性重置怎么办?
若业务要求“必须精确归零且阻塞写入”,不能依赖 reset(),应从使用层控制:
- 用外部同步机制(如
ReentrantLock)包裹sum()和reset(),确保二者原子执行 - 改用
AtomicLong:它虽性能较差,但set(0)是单变量 CAS,天然具备强一致性 - 重构为周期性新建实例:例如每分钟创建新
LongAdder,旧实例停写并归档,避免重置需求
本质上,LongAdder 是为“高频写 + 低频读”优化的,reset() 只是辅助工具,不是并发原语。用错时机,就会把性能优势变成一致性漏洞。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










