一、介绍
LongAdder是Doug Lea设计的一个线程安全的累加器,基本可以替换AtomicLong.其设计主要分为两部分,一部分是base,基础数据,如果没有数据竞争,那么就一直会对base进行cas累加;另一部分就是cell数组,该目的就是分担base的压力.举个例子,如果有一百个线程需要数据累加,AtomicLong只会一个线程去累加,其余线程自旋重试,而LongAdder可以有cell数组长度+1个线程同时累加,消费者增加,处理更快;
二、继承结构
核心的cell,base等概念,以及累加的核心逻辑,都是在striped64,下面会介绍
三、源码分析
LongAdder的入口主要是add方法
public void add(long x) {
//as cell数组的引用
// b 就是base的引用
// v 当前线程对应的cell的值
//m cell数组的长度
// a 当前线程对应的cell
Cell[] as; long b, v; int m; Cell a;
// cell初始化过了
//cas base值失败
if ((as = cells) != null || !casBase(b = base, b + x)) {
// 就是当前cell对应的cas操作是否成功,默认true
boolean uncontended = true;
//cell数组未初始化
if (as == null || (m = as.length - 1) < 0 ||
//当前线程对应的cell未初始化
(a = as[getProbe() & m]) == null ||
// 给当前cell cas加上一个值
!(uncontended = a.cas(v = a.value, v + x)))
//累加的核心累加,由父类striped64实现
longAccumulate(x, null, uncontended);
}
}
LongAdder的取值代码很简单,就是将base的值和cell数组所有元素的值;
public long sum() {
//as cell数组的引用
//a cell数组其中的桶位引用
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;
}
striped64的核心属性
@sun.misc.Contended static final class Cell {
//cell的值,用于最终结果的累加
volatile long value;
Cell(long x) { value = x; }
//cas操作,给value叠加val值
final boolean cas(long cmp, long val) {
return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);
}
// Unsafe mechanics unsafe类的引用
private static final sun.misc.Unsafe UNSAFE;
//value的偏移量
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);
}
}
}
/** Number of CPUS, to place bound on table size */
/**
* cpu核心数,是cell数组length的最大值
*/
static final int NCPU = Runtime.getRuntime().availableProcessors();
/**
* Table of cells. When non-null, size is a power of 2.
*/
/**
* cell数组
*/
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.
*/
/**
* 0表示未加锁
* 1表示加锁
*/
transient volatile int cellsBusy;
longAccumulate累加器
//这里的fn是一个函数式接口,可以由开发者处理,但是longadder设置为null
final void longAccumulate(long x, LongBinaryOperator fn,
boolean wasUncontended) {
//当前线程的hash值
int h;
//新线程默认hash值为0
if ((h = getProbe()) == 0) {
//设置一个为该线程设置一个hash值
ThreadLocalRandom.current(); // force initialization
h = getProbe();
//
wasUncontended = true;
}
//就是代表着cell数组是否需要扩容,默认不需要
boolean collide = false; // True if last slot nonempty
//死循环给cell设置value或累加value
for (;;) {
//as 还是cell数组的引用
//a 当前线程hash对应的桶位
//n是数组长度
// v 就是a的值
Cell[] as; Cell a; int n; long v;
//cell数组已经初始化了
if ((as = cells) != null && (n = as.length) > 0) {
//当前线程hash对应的桶位未初始化
//与该条件同级别的条件还有5个,只要满足一个(除了break出去的),都会更改hash值,从而重新选择 //桶位
if ((a = as[(n - 1) & h]) == null) {
//未加锁
//cellsBusy为1的情况有以下几种,其他线程遇到了会自旋等待这些操作结束(或者给base累加 完)
//(1)初始化cell数组
//(2)初始化单个cell
//(3) cell数组扩容
if (cellsBusy == 0) {
// Try to attach new Cell
Cell r = new Cell(x); // Optimistically create
//未加锁,cas获取锁成功
if (cellsBusy == 0 && casCellsBusy()) {
//设置创建标志位
boolean created = false;
try { // Recheck under lockrs
//
Cell[] rs; int m, j;
//doublechcek逻辑,该逻辑中使用了大量的doublecheck,以防止多线程情 //况下数据不准 cell数组为不为空
if ((rs = cells) != null &&
(m = rs.length) > 0 &&
//当前cell桶位是不是为空
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 cell值失败
else if (!wasUncontended) // CAS already known to fail
wasUncontended = true; // Continue after rehash
//使用cas 给cell累加x
else if (a.cas(v = a.value, ((fn == null) ? v + x :
fn.applyAsLong(v, x))))
break;
//如果当前cell数组长度大于核心线程数,则不扩容
//cells != as 是doublecheck,防止其他线程已经扩容
else if (n >= NCPU || cells != as)
collide = false; // At max size or stale
//不允许扩容,则设置扩容标记位为true
else if (!collide)
collide = true;
//未加锁且请求到锁
else if (cellsBusy == 0 && casCellsBusy()) {
try {
//doublecheck,防止其他线程已经扩容
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
}
h = advanceProbe(h);
}
//cell数组未初始化,未加锁,且未初始化,且加锁成功
else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
//初始化标记位
boolean init = false;
try { // Initialize table
//doublecheck,,防止其他线程已经初始化cell数组
if (cells == as) {
//初始化长度2
Cell[] rs = new Cell[2];
//初始化其中一个cell
rs[h & 1] = new Cell(x);
cells = rs;
init = true;
}
} finally {
//释放锁
cellsBusy = 0;
}
//跳出死循环
if (init)
break;
}
//给base值加上x
else if (casBase(v = base, ((fn == null) ? v + x :
fn.applyAsLong(v, x))))
break; // Fall back on using base
}
}
四:总结
LongAdder采取分而治之的思想减少高并发下,cas自旋导致的性能开销