LongAdder重要方法逐行解读

本文深入解析了Java并发工具类`LongAdder`的实现原理,重点介绍了`add`方法的逻辑,包括线程安全的Cell数组、CAS操作以及冲突处理策略。通过自旋、扩容和初始化机制,确保在高并发场景下的性能和准确性。
摘要由CSDN通过智能技术生成
LongAdder

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
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值