条件递增,逐步解析

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 中的方法处理
    }
}

add-方法流程图

  • 最初无竞争时只更新 base
  • 如果更新 base 失败后,首次新建一个 Cell[] 数组
  • 当多个线程竞争同一个 Cell 比较激烈时,可能就要对 Cell[] 扩容

总结

  • 如果 Cells 表为空,尝试用 CAS 更新 base 字段,成功则退出
  • 如果 Cells 表为空,CAS 更新 base 字段失败,出现竞争,uncontended 为 true,调用 longAccumulate(新建数组)
  • 如果 Cells 表非空,但当前线程映射的槽为空,uncontended 为 true,调用 longAccumulate(初始化)
  • 如果 Cells 表非空,且当前线程映射的槽非空,CAS更新 Cell 的值,成功则返回,否则,uncontended 设为 false,调用 longAccumulate(扩容)