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
中至少有2
個1
,也就是下面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次冪的數了。