LongAdder源码解析

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
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值