【JDK1.8-ConcurrentHashMap】tableSizeFor(int c)方法理解

       JDK1.8對ConcurrentHashMap進行了一些改動,因此照着源碼和網上博客看看究竟有哪些改動?還沒看一小會兒,就發現了一個方法比較硬咬不動,因此研究了一下,並記錄下對該方法的理解。
       ConcurrentHashMap有一個構造函數,請看下面!

public ConcurrentHashMap(int initialCapacity) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException();
        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
                   MAXIMUM_CAPACITY :
                   tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
        this.sizeCtl = cap;
    }

它是一個帶有參數的構造函數,可以指定ConcurrentHashMap初始化的大小,但是由於“神祕的裏力量”,ConcurrentHashMap初始化大小始終爲2冪次(爲什麼需要初始化成2的冪次呢?),例如:

 1. Map map = new ConcurrentHashMap(2)    其實初始化的大小爲4
 2. Map map = new ConcurrentHashMap(14)   其實初始化的大小爲32
 3. Map map = new ConcurrentHashMap(16)   其實初始化的大小爲32
 4. Map map = new ConcurrentHashMap(128)  其實初始化的大小爲256

是誰,將初始化的大小變爲2的冪次,是“他”,本篇主角 tableSizeFor(int c),“他”到底做了什麼,先來看看方法的全貌:

    /**
     * Returns a power of two table size for the given desired capacity.
     */
    private static final int tableSizeFor(int c) {
        int n = c - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

註釋講得不是很中國化,可能需要百度翻譯一下:

Returns a power of two table size for the given desired capacity.
中譯
給定一個期望的初始化大小值,返回一個2次冪大小值

咋一看這個方法不是很懂,很(感)(覺)(很)(高)(大)(上)(的)(樣)(子),看的一臉懵逼!
於是仔細研究了一下,下面發現很巧妙!下面解析一下,“他”是如何做到的。我們知道JAVA當中的int基本數據類型所佔的字節數是4Bytes,也就是32bits;>>> or <<<在JAVA中表示無符號移位。好的知道這些就可以開工啦!!!
1.試想一下如果c = 0也就是下面這個樣子

c:0000 0000 0000 0000 0000 0000 0000 0000  32bits

給方法裏面的代碼做上標記:
(1)int n = c - 1;
(2)n |= n >>> 1;
(3)n |= n >>> 2;
(4)n |= n >>> 4;
(5)n |= n >>> 8;
(6)n |= n >>> 16;
(7)return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
執行(1)之後c < 0很顯然最後返回的結果爲1
2.如果c > 0也就是下面這樣

c:0000 0000 0000 0000 0010 0000 0000 0010  32bits
or
c:1000 0000 0000 0000 0010 0000 0000 0010  32bits
or
c:0000 0000 0000 0100 0010 0000 1000 1010  32bits
...

可以發現如果c > 0話,就一定會出現一個分割點1在它的左邊全是0或者沒有數據了。如果我們將這個1往右移一位也就是代碼(2),再與n本身|一下,那麼n中至少有21,也就是下面c3標紅的兩個1
舉例:
c1:0000 0000 0000 0100 0010 0000 1000 1010   32bits
c2:  000 0000 0000 0010 0001 0000 0100 01010 32bits c1移一位
c3:0000 0000 0000 0110 0011 0000 1100 1111     32bits c1與c2或
接上c3執行代碼(3)也就是c3兩個紅11右移兩位(也就是c4
c3:0000 0000 0000 0110 0011 0000 1100 1111          32bits
c4:    00 0000 0000 0001 1000 1100 0011 0011 11     32bits
c5:0000 0000 0000 0111 1011 1100 1111 1111            32bits c3與c4或

如果n是夠大的話,那麼n是不是最少有四個1,然後執行(4)就是8個1,(5)就是16個1,(6)就是32個1,最終執行完(2)(3)(4)(5)(6),n如果夠大是不是32位都是1。因此,如果n > 0,經過(2)(3)(4)(5)(6)這五步,n所有有效位都能置爲1,最後執行(7)就是2次冪的數了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章