条件递增,逐步解析
LongAdder.java
/**
* Adds the given value.
*
* @param x the value to add
*/
public void add(long x) {
// as 是 Striped64 中的 cells 数组属性
// b 是 Striped64 中的 base 属性
// v 是当前线程 hash 到的 Cell 中存储的值
// m 是 cells 的长度减 1,hash 时作为掩码使用
// a 是当前线程 hash 到的 Cell
Cell[] as; long b, v; int m; Cell a;
// 首次首线程 ((as = cells) != null) 一定是 false,此时走 casBase 方法,以 CAS 的方式更新 base 值,且只有当 cas 失败时,才会走到 if 中
// 条件1:cells 不为空,说明出现过竞争,Cell[] 已创建
// 条件2:cas 操作 base 失败,说明其他线程先一步修改了 base 正在出现竞争
if ((as = cells) != null || !casBase(b = base, b + x)) {
// true 无竞争/false 表示竞争激烈
// 多个线程 hash 到同一个 Cell,
boolean uncontended = true;
// 条件1:cells 为空,说明正在出现竞争,上面是条件2过来的
// 条件2:应该不会出现
// 条件3:当前线程所在的 Cell 为空,说明当前线程没有更新过 Cell,应初始化一个 Cell
// 条件4:更新当前线程所在的 Cell 失败,说明现在竞争很激烈,多个线程 hash 到了同一个 Cell,应扩容
if (as == null || (m = as.length - 1) < 0 ||
// getProbe() 方法返回的是线程中的 threadLocalRandomProbe 字段
// 它是通过随机数生成的一个值,对于一个确定的线程这个值是固定(除非可以修改它)
(a = as[getProbe() & m]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
longAccumulate(x, null, uncontended); // 调用 Striped64 中的方法处理
}
}
- 最初无竞争时只更新 base
- 如果更新 base 失败后,首次新建一个 Cell[] 数组
- 当多个线程竞争同一个 Cell 比较激烈时,可能就要对 Cell[] 扩容
总结
- 如果 Cells 表为空,尝试用 CAS 更新 base 字段,成功则退出
- 如果 Cells 表为空,CAS 更新 base 字段失败,出现竞争,uncontended 为 true,调用 longAccumulate(新建数组)
- 如果 Cells 表非空,但当前线程映射的槽为空,uncontended 为 true,调用 longAccumulate(初始化)
- 如果 Cells 表非空,且当前线程映射的槽非空,CAS更新 Cell 的值,成功则返回,否则,uncontended 设为 false,调用 longAccumulate(扩容)