striped64的核心设计目标是降低竞争、提升并发写性能:通过将逻辑值拆分为base字段和懒初始化的cells数组(长度为2的幂,上限为cpu核数),线程基于probe哈希定位cell写入,避免争抢;cellsbusy作为volatile自旋锁控制初始化与扩容,sum()返回base与所有cell之和,保障高吞吐但最终一致性。

Striped64 的核心设计目标:降低竞争,提升并发写性能
LongAdder 不直接用 volatile long 做累加,是因为高并发下 CAS 自旋开销大、失败率高。Striped64 就是为解决这个问题而抽象出的“分段累加”基类——它把一个逻辑值拆成多个 cell(单元格),线程尽量往自己归属的 cell 写,避免争抢同一个内存位置。
cell 数组的懒初始化与动态扩容机制
cells 数组默认为 null,首次发生竞争(比如第一次 CAS 失败)时才初始化为长度 2 的数组;后续若继续冲突,会尝试扩容(翻倍),但扩容需满足两个前提:cells 未被其他线程正在扩容 且 当前数组未被扩容过(即 cellsBusy == 0)。扩容不是无限制的,上限为 CPU 核心数(Runtime.getRuntime().availableProcessors()),因为超过核数的分段对减少竞争帮助有限,反而增加哈希定位和内存开销。
线程如何定位自己的 cell:probe 值与掩码寻址
每个线程通过 ThreadLocalRandom.getProbe() 获取一个初始 probe 值(类似线程本地哈希种子),该值在首次调用时生成并绑定到线程。定位 cell 时,并不直接取模,而是用:(probe & (cells.length - 1)) —— 要求数组长度始终是 2 的幂,用位与代替取模提升效率。如果目标 cell 为空,就尝试 CAS 初始化;如果非空但 CAS 失败(说明有竞争),则触发 rehash(更新 probe)或扩容,而非死等。
base 与 cells 的协同:兜底 + 分流
Striped64 维护一个 volatile long base 字段,它既是无竞争时的累加位置,也是 cells 为 null 或扩容中时的临时写入点。所有读操作(如 sum())都必须将 base 值加上所有非空 cell 的值——这意味着 sum 是最终一致的,非实时精确值(中间可能有未合并的增量)。这种设计牺牲了强一致性,换来了写路径的极致吞吐。
关键同步控制:cellsBusy 作为自旋锁
cells 数组的初始化和扩容由一个 volatile int cellsBusy 控制,它充当轻量级锁:值为 0 表示空闲,1 表示被占用。CAS 修改 cellsBusy 成功的线程才能执行扩容逻辑,失败者让出或重试。它不用 ReentrantLock 或 synchronized,就是为了避免进入内核态,保持用户态自旋的低延迟特性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











