我不清楚你在問什麼。
你有興趣知道爲什麼HashMap不是線程安全的嗎?或者你只是想知道調整大小期間「反轉」效果的原因(這是線程不安全的原因之一)?
對於後一個問題(這是你的問題明確要求的),這裏的原因是:
通過檢查HashMap中的源代碼,有一個transfer()
方法,其負責人向條目從舊移動表到新的一個:
void transfer(Entry[] newTable) {
Entry[] src = table;
int newCapacity = newTable.length;
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);
}
}
}
反向是上述邏輯的副作用(看靠近do-while循環,它不應該是不難理解)。
如果你問他們爲什麼要讓訂單反向,那麼你最好問作者。不過,我可以告訴你,他們不打算「顛倒」訂單。由於HashMap沒有迭代次序,所以實現不需要維護任何次序。只要結果是正確的,實施者可以選擇最簡單和最快的方式來實現調整大小邏輯。目前的邏輯是他們的選擇。
更新:如果你只是想知道一個非線程安全的情況,還有其他一些更明顯的情況。
例如,添加到地圖中的條目時,邏輯是這樣的:首先計算該指數把條目,它在表中添加到該索引,如果表是「完全」,然後做調整。
有可能是,一個線程試圖添加一個條目,然後哈希碼是101,那麼它找出指標的情況下,和原來的表大小爲100,和值爲1
在這時間,另一個線程進來,並添加一個條目到表中,並發現表是「滿」,然後它進行調整大小。新表的大小現在是200
那麼在這個時候,線程1去的實際上是把條目表,並試圖把索引1.然而,隨着大小200,新表步驟正確的索引應該是101而不是1.
結果是地圖導致了一個損壞的狀態。
還有更多不同的線程不安全的例子。
對於您提到的給定示例。下面是它如何可能會導致問題的一個具體的例子:
假設現有的哈希表:
[0] -> E1 -> E2 -> E3 -> null
[1]
調整大小會做這樣的事情:
- Create a new table
(old table)
[0] -> E1 -> E2 -> E3 -> null
[1]
(new table)
[0]
[1]
[2]
[3]
- iterate thru the original entries, and put it one by one
(Put E1 to new table)
[0] - E2 -> E3
[1] \
\
v
[0] -> E1 ->null
[1]
[2]
[3]
(Put E2 to new table)
[0] ------ E3
[1] \
\
v
[0] -> E2 -> E1 ->null
[1]
[2]
[3]
你會在這一點看,指數舊錶的0仍然指向E1
如果另一個線程進來,嘗試做大小調整,做在這樣的中間狀態調整可能會導致所有這類問題:0錯誤與原始文章中一樣,或在結果表中缺少條目等。
拜託。當你可以更容易地發佈原始文本時,你是否必須創建和發佈圖片?爲什麼要在這個史詩般的規模上浪費時間和空間?考慮到你引用的同一段中給出了答案,很難看出你爲什麼要發佈這個問題。 – EJP
您的鏈接已損壞。 – djechlin
我對你在問什麼感到困惑:你有興趣知道爲什麼內部鏈表逆轉嗎?或者你想知道爲什麼HashMap不是線程安全的? –