LongAdder 的 longAccumulate 方法通过 volatile int 类型的 cellsBusy 自旋锁协调 Cells 数组扩容,仅允许一个线程执行初始化或扩容;扩容前需 CAS 获取锁,失败则扰动探针或退至 base 累加;uncontended 标志驱动冲突感知的主动扩容,失败线程降级处理保障高并发吞吐。

LongAdder 的 longAccumulate 方法在 Cells 数组扩容时,核心是通过 cellsBusy 这个 CAS 锁来协调多线程对数组的创建或扩容操作,避免并发修改导致状态不一致或重复初始化。
cellsBusy 作为轻量级自旋锁
cellsBusy 是一个 volatile int 类型变量,仅取值 0(空闲)或 1(被占用)。它不依赖系统锁或阻塞机制,而是用 UNSAFE.compareAndSwapInt(this, CELLSBUSY, 0, 1) 原子地尝试“加锁”。一旦某个线程成功将 0 改为 1,就获得唯一权限去执行 cells 初始化或扩容;其他线程检测到 cellsBusy == 1,会主动让出或重试,不会阻塞,但会短暂自旋等待。
扩容前必须先抢到 cellsBusy
当 longAccumulate 判定需要扩容(例如当前 cell 冲突频繁、数组已满且未达 CPU 核数上限),它会:
- 先调用
casCellsBusy()尝试获取锁; - 失败则继续循环,期间可能触发 probe 扰动或退回到 base 累加;
- 成功后才开始重建数组:新数组长度为原长 ×2,所有旧 cell 值按哈希映射迁移到新位置;
- 扩容完成后,将
cellsBusy重置为 0,并更新cells引用。
uncontended 参数影响扩容决策
uncontended 是调用方传入的布尔标记,表示上一次 CAS 操作是否“无竞争”成功。若为 false(即刚发生冲突),longAccumulate 会更激进地尝试扩容或新建 cell —— 它不是等数组填满才扩容,而是依据冲突信号提前干预。这使得扩容时机更贴近真实竞争压力,而非固定阈值驱动。
立即学习“Java免费学习笔记(深入)”;
失败线程不会空等,而是降级处理
抢锁失败或扩容中遇到竞争的线程,不会挂起或无限等待。它们会:
- 重新计算探针(
advanceProbe()),尝试定位另一个 cell; - 若仍不可用,可能暂时退回到
casBase更新基础值; - 极端情况下,甚至触发新一轮扩容尝试(只要未超最大容量限制)。
这种设计保证了高并发下吞吐不因锁争用而断崖下跌,也避免了传统锁带来的上下文切换开销。


















