天天看點

LongAdder源碼分析(隻分析了兩個方法,add和longAccumulate,也是核心方法)

    public void add(long x) {

        Cell[] as; long b, v; int m; Cell a;

            if ((as = cells) != null || !casBase(b = base, b + x)) {//★三種情況,這裡的cas隻嘗試一次,(在cells為空的情況下)失敗就進去

                                                                        1.cells為空,cas(false||false)成功就不進去; 

                                                                        2.cells為空且casBase失敗(false||true),要進去初始化cells     ▲

                                                                        3.cells不為空(true||{true|false}),肯定要進去嘗試優化      ▲

            boolean uncontended = true;//★初始化未争用辨別

            if (as == null || (m = as.length - 1) < 0 ||

                (a = as[getProbe() & m]) == null ||        //★擷取目前線程的probe對應的cell,如果為空得初始化

                !(uncontended = a.cas(v = a.value, v + x)))//★uncontended這個是對線程對應的cell的值進行加一操作的結果,

                                                            沖突說明了什麼?hash到同一個cell的多個線程同時操作cas,得進入下一個方法處理

                longAccumulate(x, null, uncontended);

        }

    }

    final void longAccumulate(long x, LongBinaryOperator fn,

                              boolean wasUncontended) {

        int h;

        if ((h = getProbe()) == 0) {//★第一次進入,如果hash為0,必須rehash

            //初始化ThreadLocalRandom;

            ThreadLocalRandom.current(); 

            //将h設定為0x9e3779b9

            h = getProbe();

            //設定未競争标記為true

            wasUncontended = true;//★設定hash到同一個cell上并嘗試cas這個cell的value時産生的競争,競争改value

        }

        boolean collide = false; //★修改cells起沖突了 

        for (;;) {

            Cell[] as; Cell a; int n; long v;

             if ((as = cells) != null && (n = as.length) > 0) {//★cell為空或者數組非空,可以嘗試累加

                if ((a = as[(n - 1) & h]) == null) {//★這個cell還是virgin

                    if (cellsBusy == 0) {//★cellsbusy是個自旋鎖,判斷是否可以對cells數組進行操作

                        Cell r = new Cell(x); 

                        if (cellsBusy == 0 && casCellsBusy()) {//★擷取該cell的自旋鎖成功

                            boolean created = false;

                            try {

                                Cell[] rs; int m, j;

                                if ((rs = cells) != null &&

                                    (m = rs.length) > 0 &&

                                    rs[j = (m - 1) & h] == null) {//★再次檢查是不是virgin

                                    rs[j] = r;                    //★ 将該插入的插入

                                    created = true;

                                }

                            } finally {

                                cellsBusy = 0;//★自旋鎖放開,别人可以對cells數組進行修改操作了

                            }

                            if (created)//★爽完了,可以跳出了

                                break;

                            continue;//★沒有擷取鎖,被别人爽了,繼續循環

                        }

                    }

                    collide = false;//★有别的線程擷取了這個cells數組的鎖,不能改了,重置collide,繼續下一個循環

                } else if (!wasUncontended)  

                    wasUncontended = true;//★修改cell的value競争了,設定标志位,重新循環

                else if (a.cas(v = a.value, ((fn == null) ? v + x ://★特殊情況排除,就嘗試累加cell,嘗試成功就傳回

                                             fn.applyAsLong(v, x))))

                    break;

                else if (n >= NCPU || cells != as)//★上一步争用失敗,數組越界,或者cells被修改,重置沖突标志位

                    collide = false;

                else if (!collide)

                    collide = true;//★上面全部處理失敗,肯定有沖突,将沖突标志位設定為true

                else if (cellsBusy == 0 && casCellsBusy()) {//★處理擴容(2倍)cells數組情況,擷取了cellsbusy鎖,并且他不忙

                    try {

                        if (cells == as) {      //★有可能人家改了,又釋放了鎖,檢查cells還是不是以前那個數組

                            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;           //★擴容完還得嘗試累加value        // Retry with expanded table

                }

                h = advanceProbe(h);//★上面出問題的條件語句,都必須執行這裡rehash

            }else if (cellsBusy == 0 && cells == as && casCellsBusy()) {//★未初始化且擷取了cells的自旋鎖就初始化

                boolean init = false;

                try {                           // Initialize table

                    //初始化cells數組,初始容量為2,并将x值通過hash&1,放到0個或第1個位置上

                    if (cells == as) {

                        Cell[] rs = new Cell[2];

                        rs[h & 1] = new Cell(x);

                        cells = rs;

                        init = true;

                    }

                } finally {

                    //解鎖

                    cellsBusy = 0;

                }

                //如果init為true說明初始化成功,跳出循環

                if (init)//★初始化成功

                    break;

            }

            else if (casBase(v = base, ((fn == null) ? v + x :

                                        fn.applyAsLong(v, x))))//★最次的情況,隻能在base上嘗試累加了,也就退化成atomicLong類型了

                break;                          // Fall back on using base

        }

    }

繼續閱讀