多執行緒 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:沒什麼畫圖工具 手畫了一下
參考文章:http://blog.csdn.net/xiaohui127/article/details/11928865