ConcurrentHashMap源碼解析

當(dāng)一件事你不能說明白的時(shí)候,十有八九是你還不是十分了解(自勉)

base on JDK 1.8.0_60

首先我們來看看ConcurrentHashMap整體結(jié)構(gòu),如圖所示


ConcurrentHashMap.png

ConcurrentHashMap是如何初始化?

首先我們來看看ConcurrentHashMap關(guān)于初始化比較重要的屬性

    /**
     * The array of bins. Lazily initialized upon first insertion.
     * Size is always a power of two. Accessed directly by iterators.
     */
    transient volatile Node<K,V>[] table;

    /**
     * Table initialization and resizing control.  When negative, the
     * table is being initialized or resized: -1 for initialization,
     * else -(1 + the number of active resizing threads).  Otherwise,
     * when table is null, holds the initial table size to use upon
     * creation, or 0 for default. After initialization, holds the
     * next element count value upon which to resize the table.
     */
    private transient volatile int sizeCtl;

下面我們來看看ConcurrentHashMap中的關(guān)于初始化的代碼initTable()方法

    /**
     * Initializes table, using the size recorded in sizeCtl.
     */
    private final Node<K,V>[] initTable() {
        Node<K,V>[] tab; int sc;
        //如果表為空才進(jìn)行初始化工作
        while ((tab = table) == null || tab.length == 0) {
        //如果sizeCtl小于為負(fù)數(shù)則說明有線程正在進(jìn)行初始化操作
        //當(dāng)前線程應(yīng)該放棄CPU的使用
            if ((sc = sizeCtl) < 0)
                Thread.yield(); // lost initialization race; just spin
             //否則說明尚未有線程對表進(jìn)行初始化,那么本線程就來做這個(gè)工作   
            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                try {
               //保險(xiǎn)起見,再次判斷下表是否為空
                    if ((tab = table) == null || tab.length == 0) {
                      //至此, sc 大于零說明容量已經(jīng)初始化了,否則使用默認(rèn)容量,其他線程再也無法初始化!!!
                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                        @SuppressWarnings("unchecked")
                        //構(gòu)建容量數(shù)組
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                        table = tab = nt;                       
                        //計(jì)算閾值,等效于 n*0.75
                        sc = n - (n >>> 2);
                    }
                } finally {
                    sizeCtl = sc;
                }
                break;
            }
        }
        return tab;
    }

ConcurrentHashMap是如何統(tǒng)計(jì)元素?cái)?shù)量?

首先我們來看看ConcurrentHashMap關(guān)于元素?cái)?shù)量的輔助屬性與類

    /**
     * Base counter value, used mainly when there is no contention,
     * but also as a fallback during table initialization
     * races. Updated via CAS.
     */
    private transient volatile long baseCount;

    /**
     * A padded cell for distributing counts.  Adapted from LongAdder
     * and Striped64.  See their internal docs for explanation.
     */
    @sun.misc.Contended static final class CounterCell {
        volatile long value;
        CounterCell(long x) { value = x; }
    }

下面我們來看看CouncurrentHashMap的size()方法,其中主要調(diào)用了sumCount()方法

    /**
     * {@inheritDoc}
     */
    public int size() {
        long n = sumCount();
        return ((n < 0L) ? 0 :
                (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE :
                (int)n);
    }

下面是sunCount()的源碼,可以看出ConcurrentHashMap就是通過計(jì)算baseCount與CountCell數(shù)組的值來計(jì)算ConcurrentHashMap包含的元素的數(shù)量,這就引發(fā)了一個(gè)思考,為什么ConcurrentHashMap要這樣設(shè)計(jì)來統(tǒng)計(jì)包含的元素?cái)?shù)量?


    final long sumCount() {
        CounterCell[] as = counterCells; CounterCell a;
        long sum = baseCount;
        if (as != null) {
            for (int i = 0; i < as.length; ++i) {
                if ((a = as[i]) != null)
                    sum += a.value;
            }
        }
        return sum;
    }

未完待續(xù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容