关于JDK8的LongAdder类源码解读

    public void add(long x) {
        Cell[] cs; long b, v; int m; Cell c;
        //Cell数组为null时,会尝试CAS对basecount+x。若不成功进入if
        //这里可以看到cells!=null条件的优先级高,因此Longadder会优先选择在cells中更新。
        if ((cs = cells) != null || !casBase(b = base, b + x)) {
            boolean uncontended = true;
            //CASE1:Cell数组为null
            //CASE2:Cell数组所在索引上的Cell对象是null    
            //CASE3:1、2都不是null,就尝试CAS更改该Cell中的value,并且更改失败
            //以上三种情况都会进入if
            if (cs == null || (m = cs.length - 1) < 0 ||
                (c = cs[getProbe() & m]) == null ||
                !(uncontended = c.cas(v = c.value, v + x)))
                longAccumulate(x, null, uncontended);
        }
    }

final void longAccumulate(long x, LongBinaryOperator fn,boolean wasUncontended) {
        int h;
        if ((h = getProbe()) == 0) {
            ThreadLocalRandom.current(); // force initialization
            h = getProbe();
            wasUncontended = true;
        }
        boolean collide = false;                // True if last slot nonempty
        done: for (;;) {
            Cell[] cs; Cell c; int n; long v;
            //CASE1:Cell数组已经初始化,进入if
            if ((cs = cells) != null && (n = cs.length) > 0) {
                //1.1:但是在该索引上的Cell对象为null,就需要初始化
                //    cellsBusy是对整个数组的锁标记,0是无锁,1是锁给占用
                if ((c = cs[(n - 1) & h]) == null) {
                    if (cellsBusy == 0) {       // Try to attach new Cell
                        Cell r = new Cell(x);   // Optimistically create
                        if (cellsBusy == 0 && casCellsBusy()) {
                            try {               // Recheck under lock
                                Cell[] rs; int m, j;
                                if ((rs = cells) != null &&
                                    (m = rs.length) > 0 &&
                                    rs[j = (m - 1) & h] == null) {
                                    rs[j] = r;
                                    break done;
                                }
                            } finally {
                                cellsBusy = 0;
                            }
                            continue;           // Slot is now non-empty
                        }
                    }
                    collide = false;
                }
                //1.2:这个wasUncontended看不懂有什么用
                else if (!wasUncontended)       // CAS already known to fail
                    wasUncontended = true;      // Continue after rehash
                //1.3:尝试去更新Cell中的value值,成功就结束循环break
                else if (c.cas(v = c.value,
                               (fn == null) ? v + x : fn.applyAsLong(v, x)))
                    break;
                //1.4:作为扩容上限的限制条件
                else if (n >= NCPU || cells != cs)
                    collide = false;            // At max size or stale
                //1.5:其实隐含为下一个elseif的条件,只是为了多循环一次
                else if (!collide)
                    collide = true;
                //1.6:这时候1.1~1.5都不符合,1.6进行扩容时,已经CAS了2次,需要扩容
                else if (cellsBusy == 0 && casCellsBusy()) {
                    try {
                        if (cells == cs)        // Expand table unless stale
                            cells = Arrays.copyOf(cs, n << 1);
                    } finally {
                        cellsBusy = 0;
                    }
                    collide = false;
                    continue;                   // Retry with expanded table
                }
                h = advanceProbe(h);    //每循环一次都会重新hash
            }
            //CASE2:Cell数组还没以后初始化,若拿到锁标记后,就去初始化
            else if (cellsBusy == 0 && cells == cs && casCellsBusy()) {
                try {                           // Initialize table
                    if (cells == cs) {
                        Cell[] rs = new Cell[2];
                        rs[h & 1] = new Cell(x);
                        cells = rs;
                        break done;
                    }
                } finally {
                    cellsBusy = 0;
                }
            }
            
            // Fall back on using base
            //CASE3:这是针对Cell数组没有初始化,又不满足CASE2,因为已经有线程正在初始化,无法 
            //拿到锁标记进入CASE2,这时候不能让他闲着,干脆就让他去CAS更新BaseCount的值
            else if (casBase(v = base,
                             (fn == null) ? v + x : fn.applyAsLong(v, x)))
                break done;
        }
    }

总结:

add跳入LongAccumulate三个”或“条件:

1、Cell数组未初始化 

2、在所求得的索引的数组元素未初始化 

3、对数组元素的CAS失败

LongAccumulate里循环内的三个大分支:

CASE1:Cell数组初始化了。

那就针对2、3条件包括进行Cell初始化、重新哈希、扩容、数组元素CAS的操作并且break。

CASE2:能拿到cellsBusy=0,且Cell数组未初始化。

那就进行数组初始化,然后继续下一轮循环

CASE3:Cell数组未初始化,但锁又被执行CASE2情况的线程占用中

此时有线程在进行线程初始化,就干脆尝试CAS更新BaseCount的值

意义:高并发下更加优秀的计数方案

AtomicLong原子类在高并发的场景下,虽然他能够解决线程安全的问题,效率不高,会有大量的线程CAS失败,x个线程同时进行CAS,有x-1的CAS都会失败,因此CAS+自旋反而成为性能瓶颈

LongAdder实现原理是采用空间换时间的思想,用Cell数组来分散所有线程访问Basecount的压力,不过这里有个叫做”内存伪共享“的概念。

Cell数组是内存中连续的一块空间,这块空间倘若作为一个缓存块,缓存到Cache中去,如果修改其中某个Cell对象,会导致缓存块的失效,很显然会带来严重的缓存开销。解决方案就是“填充”,让每个Cell处于不同的缓存块中,这里一样贯彻的是空间换时间的理念。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值