一、AtomicLong 的瓶颈:单点 CAS 竞争
AtomicLong 内部只有一个 volatile long value,所有线程并发自增/自减时,全部争抢同一个变量的 CAS 权限。
- 低并发:CAS 成功率高,性能好。
- 高并发(如 1000+ 线程):
- CAS 大量失败 → 线程自旋重试 → CPU 飙高。
- 重试越多,冲突越剧烈,形成恶性循环,QPS 断崖式下跌。 本质:单点热点,所有线程挤一条独木桥。
二、LongAdder 的核心思想:热点分散到多个 Cell
JDK1.8 引入 LongAdder,核心是分段计数、分散热点:把一个 value 拆成 base + Cell[] 数组,用空间换时间,将单点竞争分散到多个独立的 Cell 上。
1. 核心结构(父类 Striped64)
transient volatile long base; // 基础值(低并发用)
transient volatile Cell[] cells; // 分段数组(高并发用,2的幂次方)
transient volatile int cellsBusy; // 扩容/初始化时的自旋锁
@sun.misc.Contended // 伪共享防护:每个Cell独占缓存行
static final class Cell {
volatile long value;
boolean cas(long cmp, long val); // 仅更新当前Cell的CAS
}
- base:低并发时直接 CAS 更新,等价于 AtomicLong。
- Cell[]:高并发时启用,每个 Cell 是独立的原子变量,线程只更新自己映射到的 Cell。
- @Contended:解决伪共享(多个 Cell 挤在一个 CPU 缓存行,一个修改导致其他缓存失效),每个 Cell 独占 64 字节缓存行。
2. 工作流程(add(x) 方法)
- 无竞争/低并发:直接 CAS 更新
base,成功返回。 - 首次 CAS 失败(有竞争):
- 初始化
cells数组(默认长度 2)。 - 线程用
ThreadLocalRandom.getProbe()哈希 → 映射到某个 Cell 槽位。
- 初始化
- 高并发/Cell 冲突:
- 线程只对自己的 Cell 做 CAS,不同线程操作不同 Cell,冲突概率指数级下降。
- 若当前 Cell 仍冲突:rehash 换槽位;冲突严重时扩容 cells(2→4→8…≤CPU核数),进一步分散压力。
- 取值(sum()):
base + 所有 Cell.value累加,最终一致,非强实时。
三、AtomicLong vs LongAdder 对比
| 维度 | AtomicLong | LongAdder |
|---|---|---|
| 竞争模型 | 单点 CAS,所有线程抢一个 value | 多点 CAS,线程分散到不同 Cell |
| 高并发性能 | 差(自旋多、CPU高) | 极好(冲突少、CPU低) |
| 低并发性能 | 优(无额外开销) | 略差(需维护 cells) |
| 读取精度 | 强一致(实时准确) | 最终一致(sum() 有短暂误差) |
| 内存占用 | 小(仅1个 long) | 大(Cell 数组,随并发扩容) |
| 适用场景 | 读多写少、强一致、低并发 | 写多读少、计数统计、高并发 |
四、为什么能解决 CAS 争抢?(关键)
- 热点分散:把 1 个竞争点拆成 N 个(N=cells.length),冲突概率从 100% 降到 1/N。
- 无锁化分段:线程只操作自己的 Cell,互不干扰,无需等待其他线程。
- 动态扩容:并发越高,cells 越大,分散效果越好,自适应压力。
- 伪共享防护:@Contended 让每个 Cell 独占缓存行,避免“修改一个、影响一群”的缓存颠簸。
五、代码示例:替换 AtomicLong 为 LongAdder
1. AtomicLong(高并发下性能差)
AtomicLong counter = new AtomicLong(0);
// 多线程并发自增
counter.incrementAndGet();
2. LongAdder(高并发推荐)
LongAdder counter = new LongAdder();
// 多线程并发自增(无锁、分散到不同Cell)
counter.increment();
// 最终取值(累加base+所有Cell)
long total = counter.sum();
六、适用场景与注意事项
✅ 推荐用 LongAdder
- 高并发计数(如接口 QPS、订单数、统计指标)。
- 写多读少,允许最终一致性(非实时精确)。
- 并发线程数 ≥ CPU 核数(冲突明显)。
❌ 不推荐用 LongAdder
- 读多写少、低并发(AtomicLong 更省内存、更快)。
- 要求强一致性实时值(如金融交易金额)。
- 需要精确的 CAS 结果(如
compareAndSet逻辑)。
七、总结
- AtomicLong:单点 CAS,高并发下竞争激烈、性能雪崩。
- LongAdder:base + Cell[] 分段计数,把单点热点分散到多个 Cell,线程仅竞争自己的 Cell,冲突概率指数级下降,高并发性能提升数倍到数十倍。
- 本质:用空间换时间,分而治之,消除单点瓶颈。
注意:本文归作者所有,未经作者允许,不得转载