Skip to Content
面试题库Juc[面试题] AtomicInteger 和 LongAdder 有什么区别?为什么高并发计数更推荐 LongAdder?

[面试题] AtomicInteger 和 LongAdder 有什么区别?为什么高并发计数更推荐 LongAdder?

📖 版块 A:知识讲解版 (温故知新)

  • AtomicInteger

    1. 基于单个共享变量 + CAS 实现原子更新。
    2. 适合竞争不激烈的计数场景。
  • LongAdder

    1. 基于 分段累加 思想。
    2. 除了一个基础值 base 之外,还维护一组 Cell
    3. 多个线程会把更新压力分散到不同 Cell 上,减少对同一个热点变量的 CAS 冲突。
  • 核心区别

    1. 低并发AtomicInteger 更简单,开销小。
    2. 高并发写LongAdder 吞吐量通常更好。
    3. 取值方式LongAdder.sum() 需要把多个槽位求和,因此读取不是单变量瞬时值那种严格语义。
  • 为什么 LongAdder 更快

    • 它用“空间换时间”,把单点竞争打散成多点竞争,降低自旋失败概率。
  • 适用场景

    1. QPS 统计。
    2. 监控指标累加。
    3. 高并发访问计数。
  • 不适用场景

    • 既要求高并发更新,又要求每次读取都必须拿到严格即时一致值的金融类场景。

🎤 版块 B:面试实战版 (高手逐字稿)

Q:AtomicInteger 和 LongAdder 有什么区别?为什么高并发计数更推荐 LongAdder?

💬 高手逐字稿

AtomicIntegerLongAdder 都能做线程安全计数,但它们适合的并发强度不一样。

AtomicInteger 的实现很直接,就是围绕一个共享变量做 CAS。比如自增的时候,它会不断尝试读取旧值、计算新值、再 CAS 回去。如果并发不高,这种方式非常轻量,也很好理解。

但问题在于,高并发下所有线程都去抢同一个变量,CAS 冲突会非常严重。大量线程不断自旋重试,CPU 就会空转,吞吐量开始明显下降。

LongAdder 的优化思路就是把这个“单点热点”拆掉。它内部不只维护一个值,而是维护一个 base 加上一个 Cell 数组。线程更新时,不再都去打同一个点,而是尽量分散到不同的 Cell 上做 CAS。最后读取总值时,再把 base 和所有 Cell 加起来。这个设计本质上就是用更多内存槽位,换更低的冲突概率

所以为什么高并发计数更推荐 LongAdder?因为它把本来所有线程都挤在同一个收费口的问题,变成了多个收费口并行通行。在监控指标、访问次数统计、QPS 计数这种“写很多、读结果只是做统计”的场景里,它通常比 AtomicInteger 吞吐量高很多。

不过它不是无脑替代。LongAdder 读取时要做聚合,所以它更偏统计语义,而不是那种每一步都要求精确可观察的强一致计数。如果业务是转账流水、库存扣减这种严格场景,我还是会优先考虑 CAS + 业务控制,甚至直接用锁,而不是只看吞吐量。

最后更新于:
⏱️

登录后开始阅读

当前 MVP 版本只开放邮箱密码登录注册。完成登录后即可进入面试题内容。

还没有账号?先去注册