多執行緒 HashMap 死迴圈 問題解析

美式不加糖_發表於2017-12-24

多執行緒 HashMap 死迴圈 問題解析

原始碼

resize

    void resize(int newCapacity)  
    {  
        Entry[] oldTable = table;  
        int oldCapacity = oldTable.length;  
        ......  
        //建立一個新的Hash Table  
        Entry[] newTable = new Entry[newCapacity];  
        //將Old Hash Table上的資料遷移到New Hash Table上  
        transfer(newTable);  
        table = newTable;  
        threshold = (int)(newCapacity * loadFactor);  
    }  
複製程式碼

遷移

    void transfer(Entry[] newTable)  
    {  
        Entry[] src = table;  
        int newCapacity = newTable.length;  
        //下面這段程式碼的意思是:  
        //  從OldTable裡摘一個元素出來,然後放到NewTable中  
        for (int j = 0; j < src.length; j++) {  
            Entry<K,V> e = src[j];  
            if (e != null) {  
                src[j] = null;  
                do {  
                    Entry<K,V> next = e.next;  
                    int i = indexFor(e.hash, newCapacity);  
                    e.next = newTable[i];  
                    newTable[i] = e;  
                    e = next;  
                } while (e != null);  
            }  
        }  
    }  
複製程式碼

我們可以知道newTable 是新建立的 是執行緒私有的, 因為 執行緒1 獲取 e 和next 之後 執行緒2 插入執行了,執行完是 倒序的鏈條, 執行緒1 再插入 e 和next的 方向 與 執行緒2執行之後的 方向不對應 導致 迴圈兩次之後 出現問題,會丟資料 ,問題主要集中在最後一次(第3此)執行之後 e,next 均指向null 迴圈結束

丟資料的問題比較大,

兩個執行緒 ,

do {  
    Entry<K,V> next = e.next; // <--假設執行緒一執行到這裡就被排程掛起了  
    int i = indexFor(e.hash, newCapacity);  
    e.next = newTable[i];  
    newTable[i] = e;  
    e = next;  
} while (e != null); 
複製程式碼

原來:3 -> 7 -> 6 -> 5( 資料5 resize的時候 分到了其他陣列 這裡不管它 )

執行緒1 在 上圖位置 卡住, e1 指向3 和 next1 指向 7

執行緒2 執行

執行後結果為 6 -> 7 -> 3 -> null

ps:沒什麼畫圖工具 手畫了一下

多執行緒 HashMap 死迴圈 問題解析

參考文章:http://blog.csdn.net/xiaohui127/article/details/11928865

相關文章