JDK1.7HashMap多執行緒問題
Java技術交流群:737698533
HashMap在多執行緒情況下是不安全的,一個是資料的準確性問題,一個就是可能會出現死鎖問題
出現死鎖的情況在擴容的程式碼裡,假設現在有兩個執行緒都在對下圖的Map進行操作
這個HashMap設定了初始大小為4,負載因子為0.75,現在又新增一個元素D,很不幸通過indexOf方法算出的下標也是在下標0的位置
根據擴容的判斷條件if ((size >= threshold) && (null != table[bucketIndex]))
總元素個數為3>=(陣列長度4*負載因子0.75)
而且新增的位置不為空,所以進入擴容方法
現在有T1和T2兩個執行緒同時進行新增操作,同時進行擴容
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<k,v> e : table) {
while(null != e) {
Entry<k,v> next = e.next;
//假設在這個位置T2時間片用完
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
假設T2因為時間片用完輪到T1執行,那麼此時T2執行緒的變數賦值如下,後面的陣列就不畫了
T1建立新的陣列然後將資料轉移,完成後T2醒來,如下圖所示
注意當T1將資料移動後,資料順序反了,可以看看上面的程式碼推理一下,那麼假設現線上程T2醒來,繼續執行程式碼
主要程式碼如下,下面一步程式碼對比一個圖
while(null != e) {
Entry<k,v> next = e.next;
//醒來繼續執行,計算下標
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
e.next = newTable[i];
newTable[i] = e;
e = next;
回到迴圈,判斷e不為空,繼續執行
Entry<k,v> next = e.next;
然後計算下標,繼續程式碼
e.next = newTable[i];
newTable[i] = e;
e = next;
繼續迴圈,e不為空
Entry<k,v> next = e.next;
e.next = newTable[i];
newTable[i] = e;
e = next;
這裡已經出現問題了,兩個節點互相引用