JDK1.7HashMap死鎖

Jame!發表於2021-08-01

JDK1.7HashMap多執行緒問題

Java技術交流群:737698533

在看之前可以先看看JDK1.7的Hashmap的原始碼

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;

這裡已經出現問題了,兩個節點互相引用

相關文章