【Java】JDK1.8之前HashMap併發情況為什麼會發生死迴圈
原帖地址:https://www.jianshu.com/p/4930801e23c8
進行put操作到閾值時,進行擴容的時候會導致死迴圈
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;
//計算節點在新的Map中的位置
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
假設hash演算法就是簡單的用key mod Entry陣列的長度
假設hash演算法就是簡單的用key mod Entry陣列的長度。這裡一定注意e和next的指向,當併發resize()時,這兩個指標對於死鎖產生起著至關重要的作用。根據方法執行情況,原Map中的連結串列元素在新的Map中將順序顛倒,如上圖所示,經過一次resize()後key為7的節點排在了key為3的節點之前。
do {
Entry<K,V> next = e.next;
//計算節點在新的Map中的位置
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
再次黏貼這段程式碼就是強調這個do while迴圈就是產生死鎖的罪魁禍首。下面模擬死鎖產生的過程。
注意,並非所有情況下都會產生死鎖,這也需要執行緒之間的默契配合,怎麼講呢,如圖所示:
①此時執行緒一,e指向key為3的節點,next指向key為7的節點。這點很重要,記下來。去執行執行緒二。
②假設執行緒二正常執行,結束後的狀態如下:
③此時執行緒一被喚醒,執行緒一的工作空間裡,e和next指向的元素依舊是key為3和7的節點。執行緒一開始執行。
④目前還沒發生問題,執行緒一接著工作。把key(7)摘下來,放到newTable[i]的第一個,然後把e和next往下移。
e.next = newTable[i] 導致 key(3).next 指向了 key(7)。注意:此時的key(7).next 已經指向了key(3), 環形連結串列就這樣出現了。
*轉載者總結:
根本原因是JDK1.8之前的擴容會將結點倒序
其實也就是併發時,將舊陣列的資料移到新陣列對應位置時,該位置上不能有舊陣列上的資料,否則就會形成環。
JDK1.8的解決(四個指標)
通過兩個指標loHead/loTail指向重hash後位置不變的連結串列頭和尾
以及hiHead/hiTail指向重hash後位置+oldCap的連結串列頭和尾
來避免倒序的問題,從而解決死迴圈的問題。
但是HashMap還是有併發問題,所以還是要用ConcurrentHashMap
相關文章
- HashMap多執行緒下發生死迴圈的原因HashMap執行緒
- jdk1.7中hashmap擴容時不會產生死迴圈JDKHashMap
- Linux中什麼情況下會發生程式排程?Linux
- java併發之hashmap原始碼JavaHashMap原始碼
- Spring——為什麼會有迴圈依賴(原始碼)Spring原始碼
- Java集合——HashMap(jdk1.8)JavaHashMapJDK
- 【Java併發程式設計】一、為什麼需要學習併發程式設計?Java程式設計
- java面試一日一題:講下在什麼情況下會發生類載入Java面試
- 當css中background或background-image的值為url()或url(#)時,會發生什麼情況?為什麼?如何解決?CSS
- 為什麼分散式限流會出現不均衡的情況?分散式
- 爬蟲代理為什麼會出現超時的情況?爬蟲
- 什麼情況!華為開源JDK!JDK
- MySQL會發生死鎖嗎?MySql
- 什麼情況下會出現css阻塞?CSS
- 什麼情況下會出現js阻塞?JS
- 下一個成為IE會不會是Chrome,看看是什麼情況。Chrome
- java開發需要會什麼?Java
- Java併發程式設計——為什麼要用volatile關鍵字Java程式設計
- Java併發指南13:Java 中的 HashMap 和 ConcurrentHashMap 全解析JavaHashMap
- 如果列表元素li的兄弟元素為div,會產生什麼情況?
- Java類什麼情況下被初始化?Java
- Java HashMap 原始碼逐行解析(JDK1.8)JavaHashMap原始碼JDK
- js中為什麼for迴圈比forEach效能高?JS
- 伺服器過載會出現什麼情況伺服器
- 併發數、併發以及高併發分別是什麼意思?
- Python迴圈引用是什麼?如何避免迴圈引用?Python
- 什麼是高併發,怎麼解決高併發
- PHP高併發情況下防止商品庫存超賣PHP
- 什麼是java序列化?什麼情況下需要序列化?Java
- Nature回應:為什麼在沒有程式碼的情況下發布AlphaFold3?
- [20220216]為什麼出現這樣的情況.txt
- 為什麼要有事件迴圈機制(Event Loop)事件OOP
- Snowflake(雪花演算法),什麼情況下會衝突?演算法
- Java:併發不易,先學會用Java
- Java併發中volatile和happen before是什麼? - javarevisitedJavaAPP
- Java併發指南13:Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析JavaHashMap
- Java迴圈Java
- Java 可以採用什麼語句跳出迴圈語句Java