add(long x)
public void add(long x) {
//as 表示cells的引用
//b 表示获取的base值
//v 表示期望值
//m 表示cells数组的长度
// a 表示当前线程命中的cell的单元格
Cell[] as; long b, v; int m; Cell a;
//条件一: true -> 表示cells已经被初始化过,当前线程应该将数据写入到对应的cell中
// false -> 表示cells没有被初始化过,当前所有线程应该将数据写到base中
//条件二: true -> 表示当前线程CAS替换数据成功
// false -> 替换失败,发生了竞争,可能需要重试或扩容
if ((as = cells) != null || !casBase(b = base, b + x)) {
//进来的条件:
//1.true -> 表示cells已经被初始化过,当前线程应该将数据写入到对应的cell中
//2.false -> 替换失败,发生了竞争,可能需要重试或扩容
//true -> 未竞争 false -> 发生了竞争
boolean uncontended = true;
//条件一: true -> cells没有初始化,也就是替换失败,发生了竞争进来的
// false -> cells初始化过了,当前线程应该去找自己的cell写值
//条件二: getProbe() 获取当前线程的hash值
// true -> 当前线程对应的cells数组里面的cell为null,需要创建longAccumulate来支持
// false -> 说明当前线程对应的cells数组里面的cell不为null,下一步需要将x的值添加到cell中
if (as == null || (m = as.length - 1) < 0 ||
(a = as[getProbe() & m]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
//调用这个方法的情况:
//1.true -> cells没有初始化,也就是替换失败,发生了竞争进来的【重试|初始化cells】
//2.true -> 当前线程对应的cells数组里面的cell为null,需要创建longAccumulate来支持
//3.cas失败【重试|扩容】
longAccumulate(x, null, uncontended);
}
}
类Striped64的方法,LongAdder继承了Striped64
longAccumulate(long x, LongBinaryOperator fn, boolean wasUncontended)
//1.true -> cells没有初始化,也就是替换失败,发生了竞争进来的【重试|初始化cells】
//2.true -> 当前线程对应的cells数组里面的cell为null,需要创建longAccumulate来支持
//3.cas失败【重试|扩容】
//wasUncontended :只有cells初始化之后,并且当前线程 竞争修改失败,才会是false
final void longAccumulate(long x, LongBinaryOperator fn, boolean wasUncontended) {
int h;//h表示当前线程的hash值
//条件成立,则说明当前线程 还没有分配hash值
if ((h = getProbe()) == 0) {
ThreadLocalRandom.current(); // force initialization 给当前线程分配hash值
h = getProbe();//得到hash值
wasUncontended = true;//因为默认情况下,肯定是写到了 cells[0]位置,在cell[0]的位置发生了竞争,但是不把它当作是一次真正的竞争
}
//表示扩容意向 false 一定不会扩容 true 可能会扩容
boolean collide = false; // True if last slot nonempty
//自旋
for (;;) {
//as 表示 cells引用
//a 表示当前线程命中的cell
//n 表示cells数组长度
//v 表示期望值
Cell[] as; Cell a; int n; long v;
//case1:cells已经被初始化了,当前线程应该将数据写入到对应的cell中
if ((as = cells) != null && (n = as.length) > 0) {
//当前线程对应的cells数组里面的cell为null a是当前线程对应的cell的值
if ((a = as[(n - 1) & h]) == null) {
//没有被加锁
if (cellsBusy == 0) { // Try to attach new Cell------------------------
Cell r = new Cell(x); // Optimistically create
//dcl 并且对cells加锁
if (cellsBusy == 0 && casCellsBusy()) {
boolean created = false;
try { // Recheck under lock
//rs : 当前cells
//m : cells的长度
// j : 当前线程对应的cells数组的cell的下标
//如果满足下面的所有条件,说明还没有被放置过内容,那么将r 放进去
Cell[] rs; int m, j;
if ((rs = cells) != null &&
(m = rs.length) > 0 &&
rs[j = (m - 1) & h] == null) {
rs[j] = r;
created = true;
}
} finally {
//释放锁
cellsBusy = 0;
}
if (created)
break;
continue; // Slot is now non-empty
}
}//----------------------------------
collide = false;
}
//前置条件:a 不是null
//只有当CAS修改遇到竞争 修改失败的时候,wasUncontended才会是false
else if (!wasUncontended) // CAS already known to fail
wasUncontended = true; // 准备重新hash,将wasUncontended改为true,因为新的hash值还没有竞争过
//试着将 x 加到 a 的value中 加成功,则直接结束
else if (a.cas(v = a.value, ((fn == null) ? v + x :
fn.applyAsLong(v, x))))
break;
//大于等于CPU的最大核数 或 cells被别的线程扩容过 collide=false 就不扩容了
else if (n >= NCPU || cells != as)
collide = false; // At max size or stale
//如果到了这里, collide 设置为true 则可能会扩容
else if (!collide)
collide = true;
//对cells加锁 下面准备扩容
else if (cellsBusy == 0 && casCellsBusy()) {
try {
//dcl
if (cells == as) { // Expand table unless stale
//扩大一倍
Cell[] rs = new Cell[n << 1];
for (int i = 0; i < n; ++i)
rs[i] = as[i];
cells = rs;
}
} finally {
//释放锁
cellsBusy = 0;
}
//扩容意向设置为 false
collide = false;
continue; // Retry with expanded table
}
//进行重hash
h = advanceProbe(h);
}
//前置条件:cells还未被初始化,as为null
//cellsBusy == 0 当前还未被加锁
//cells == as dcl
//casCellsBusy 将cellsBusy改为1 加锁
else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
boolean init = false;
try { // Initialize table
//dcl 下面是初始化cells的代码
if (cells == as) {
Cell[] rs = new Cell[2];
rs[h & 1] = new Cell(x);
cells = rs;
init = true;
}
} finally {
//释放锁
cellsBusy = 0;
}
if (init)
break;
}
//前置条件:cells还未被初始化其他线程正在初始化cells cellsBusy!=0 cells被加锁了
//将x加在base上
else if (casBase(v = base, ((fn == null) ? v + x :
fn.applyAsLong(v, x))))
break; // Fall back on using base
}
}