LongAdder源码解析
原理,用法和AtomaitcLong差不多,线程数少的时候原子变量占优,原子类内部是cas加循环
线程多的时候Longadder占优,内部是一个base值和一个数组,线程判断数组是不是存在,不存在就对base进行cas,失败就去对应数组里把要修改的值进行添加
数组存在会直接去数组对应cell添加值
最后把数组内的所有值和base相加返回
继承Striped64
内部数组元素类cell
@sun.misc.Contended static final class Cell {
// 保证线程可以直接读到数据
volatile long value;
Cell(long x) { value = x; }
// cas操作
final boolean cas(long cmp, long val) {
return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long valueOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> ak = Cell.class;
valueOffset = UNSAFE.objectFieldOffset
(ak.getDeclaredField("value"));
} catch (Exception e) {
throw new Error(e);
}
}
}
元素属性
/**
* Table of cells. When non-null, size is a power of 2.
内部数组2的倍数,最大为cpu核数
*/
transient volatile Cell[] cells;
/**
* Base value, used mainly when there is no contention, but also as
* a fallback during table initialization races. Updated via CAS.
基础数值
*/
transient volatile long base;
/**
* Spinlock (locked via CAS) used when resizing and/or creating Cells.
对cell数组操作时的锁,扩容初始化,cell元素赋值时需要用到
*/
transient volatile int cellsBusy;
longadder的添加方法
// 添加方法
public void add(long x) {
Cell[] as; long b, v; int m; Cell a;
// as为cell数组引用不为空,说明有线程竞争。已经创建了cell数组
// cell为空进行cas操作,操作失败进行数组中元素添加
if ((as = cells) != null || !casBase(b = base, b + x)) {
// uncontended表明没有有线程竞争
boolean uncontended = true;
// as为null表明,线程cas失败,cell数组还未创建
// m赋值,并且cell数组长度为0
if (as == null || (m = as.length - 1) < 0 ||
// 当前线程定位到数组位置上的cell元素,cell为空,表明还没被创建
(a = as[getProbe() & m]) == null ||
// 当前线程定位到的数组位置上的cell不为空,cas成功跳出判断,cas失败,说明多个线程竞争
!(uncontended = a.cas(v = a.value, v + x)))
// 当前线程去cell数组中添加vale
// cell数组可以为初始化
// cell数组中的cell元素可能为初始化
longAccumulate(x, null, uncontended);
}
}
longadder的求和方法
// 遍历cell数组,吧内部元素和base相加返回
// 返回的数值不一定是一个原子值
// 并发情况下可能不准确
public long sum() {
Cell[] as = cells; Cell a;
long sum = base;
if (as != null) {
for (int i = 0; i < as.length; ++i) {
if ((a = as[i]) != null)
sum += a.value;
}
}
return sum;
}
数组值添加
// x添加值
// fn null 写死
// wasUncontended 没有竞争 只有数组中对应位置cell添加值cas失败才是false
final void longAccumulate(long x, LongBinaryOperator fn,
boolean wasUncontended) {
int h;
// getProbe()返回线程探针值,相当于hash
// h等于0 表示线程探针没有初始化
if ((h = getProbe()) == 0) {
// 探针初始化
ThreadLocalRandom.current(); // force initialization
h = getProbe();
// cell数组cell进行cas操作时,线程探针可以没有初始化,所以对cell操作都是在0位置上,导致多个线程都在一个位置,所以造成了线程竞争,这边暂时把竞争参数改为true,暂时默认表明线程探针初始化后,会在cell数组不同位置上进行cas,不会造成竞争
wasUncontended = true;
}
// 是否有冲突
boolean collide = false; // True if last slot nonempty
// 循环,直到把值添加到数组或者添加到base上
for (;;) {
Cell[] as; Cell a; int n; long v;
// cell数组已经初始化
if ((as = cells) != null && (n = as.length) > 0) {
// 线程和数组长度减一与运算得到线程操作数组下标位置的cell,cell为空
//
if ((a = as[(n - 1) & h]) == null) {
// 判断是否可以获取锁
if (cellsBusy == 0) {// Try to attach new Cell
// 创建cell
Cell r = new Cell(x); // Optimistically create
// 获取锁
if (cellsBusy == 0 && casCellsBusy()) {
boolean created = false;
try { // Recheck under lock
Cell[] rs; int m, j;
// cell数组不为空,线程对应位置上cell为空,把新建的cell填充进去
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;
}
// 线程已经初始化探针,并且需要操作的位置上存在值了,对值得cas操作失败,吧竞争参数改成true,未竞争
// 线程需要重新修改探针值
else if (!wasUncontended) // CAS already known to fail
wasUncontended = true; // Continue after rehash
//线程需要操作的数组的下标位置存在值,对值进行cas操作,成功返回
else if (a.cas(v = a.value, ((fn == null) ? v + x :
fn.applyAsLong(v, x))))
break;
//线程有冲突,并且cell数组长度大于cpu核数,或者cell数组已经扩容过了
else if (n >= NCPU || cells != as)
// 没有冲突,表明扩容到最大
collide = false; // At max size or stale
// 没有扩容,并且没有冲突,暂时变成可以扩容
else if (!collide)
collide = true;
// 获取数组锁
else if (cellsBusy == 0 && casCellsBusy()) {
try {
// 判断其他线程是否已经扩容
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;
}
// 不需要扩容
collide = false;
continue; // Retry with expanded table
}
// 修改线程的探针
h = advanceProbe(h);
}
// 数组为初始化,锁没有被占有,进行锁的抢夺
else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
// 设置init标识符false
boolean init = false;
try { // Initialize table
// 再次判断cell数组是否为空,可能有的线程会在前一个判断数组为空后停止,然后启动的时候又恰好拿到锁,这个时候别人已经初始化数组了
if (cells == as) {
// 创建数组长度为2
Cell[] rs = new Cell[2];
// 线程探针和数组长度减一进行与运算找到线程需要再数组创建cell并且赋值的位置。
rs[h & 1] = new Cell(x);
cells = rs;
// 表明已经初始化
init = true;
}
} finally {
// 初始化了数组cell,并且在相应位置上赋值了
// 已经有线程初始化了cell数组,释放锁,
cellsBusy = 0;
}
if (init)
// 线程在cell数组上创建了cell,直接返回
break;
}
// 数组没有初始化,对数组操作的锁被其他线程持有,对基础值base进行cas,成功跳出循环,否则再次循环
else if (casBase(v = base, ((fn == null) ? v + x :
fn.applyAsLong(v, x))))
break; // Fall back on using base
}
}