concurrenthashmap + longadder 更快是因为longadder将累加分散到多个cell,避免高并发下的cas重试竞争;而concurrenthashmap的compute/merge仍存在锁或cas冲突,尤其在万级tps时cpu大量耗在重试上。

为什么 ConcurrentHashMap + LongAdder 比直接用 ConcurrentHashMap<long></long> 更快
因为 ConcurrentHashMap 的 compute 或 merge 方法在高并发下仍会触发锁竞争(哪怕只是分段锁或 CAS 重试),而 LongAdder 把计数分散到多个单元,写操作几乎无冲突。你不是在“更新一个值”,而是在“往不同槽里加一”,最后才汇总——这对高频累加场景就是质变。
常见错误现象:ConcurrentHashMap.compute(key, (k, v) -> v == null ? 1L : v + 1) 在万级 TPS 下 CPU 花费大量时间在 CAS 失败重试上,LongAdder.sum() 却稳定低开销。
- 适用场景:统计请求量、缓存命中次数、接口调用量等纯累加型指标
- 不适用场景:需要原子读-改-写(比如“如果小于阈值才加”)、或要求严格实时一致性的计数
-
LongAdder不是线程安全的“变量替代品”,它不能直接当long用;必须用sum()或longValue()获取当前值
怎么把 LongAdder 存进 ConcurrentHashMap 并避免内存泄漏
不能直接 new 一个 LongAdder 放进去就完事——如果 key 长期不访问,对应 LongAdder 实例会一直占着内存,且 ConcurrentHashMap 不会自动清理未使用的计数器。
正确做法是结合 computeIfAbsent 按需创建,并配合弱引用或定期清理逻辑(视业务周期而定):
Map<String, LongAdder> counters = new ConcurrentHashMap<>();
// 安全获取并累加
counters.computeIfAbsent("api/login", k -> new LongAdder()).increment();
- 每次
computeIfAbsent都是无锁路径,只有首次 put 时才可能有轻微竞争 - 不要用
getOrDefault(key, new LongAdder())—— 这会每次新建实例,造成对象爆炸和 GC 压力 - 如果 key 有明确生命周期(如用户 session ID),建议搭配
ScheduledExecutorService定期扫描过期 key 并remove
ConcurrentHashMap 的遍历与快照一致性问题
ConcurrentHashMap 迭代器是弱一致的,遍历时其他线程仍在写 LongAdder,所以你拿到的 sum() 只是那一刻的近似值——这不是 bug,是设计使然。
如果你需要“某一时刻所有计数器的总和”,不能边遍历边加,而要先收集所有 LongAdder 引用,再统一调用 sum():
List<LongAdder> adders = new ArrayList<>(counters.values()); long total = adders.stream().mapToLong(LongAdder::sum).sum();
- 避免在遍历
entrySet()时直接调用getValue().sum()—— 中间可能被其他线程修改,结果不可重现 -
LongAdder.sum()是非阻塞的,但多次调用之间没有顺序保证;一次收集 + 一次批量 sum 才接近“快照”语义 - 如果对一致性要求极高(比如计费场景),这种组合就不适合;该换
StampedLock+long[]或专用指标库(如 Micrometer)
LongAdder 和 AtomicLong 在什么情况下反而更慢
当并发度极低(比如单线程反复调用),LongAdder 的内部 cell 分配、跳转、分支预测开销反而比 AtomicLong 的单 CAS 更重。
- 实测显示:QPS AtomicLong.incrementAndGet() 通常快 10%–20%
-
LongAdder的优势从几百次/秒写操作开始显现,在数千以上才真正拉开差距 - 别为了“看起来高级”强行替换;压测你的实际负载路径,看
ThreadMXBean.getThreadCpuTime()或 Arthas trace 结果
最易被忽略的一点:LongAdder 的内存占用是 AtomicLong 的数倍(默认最多 128 个 cell),小堆或大量 key 场景下容易推高 GC 频率——不是所有“高效”都只看吞吐。










