HashMap併發下死迴圈問題解析
首先小夥伴要明確:死迴圈問題在JDK 1.8 之前是存在的,JDK 1.8 通過增加loHead和loTail進行了修復。
在JDK 1.7及之前 HashMap在併發情況下導致迴圈問題,致使伺服器cpu飆升至100%,那麼今天就來解析一下執行緒不安全的HashMap在高併發的情況下是如何造成死迴圈的。
要探究hashmap死迴圈的原因 首先要知道hashmap的原始碼 這樣才能從根本上對hashmap進行理解 。
首先hashmap進行元素的插入,在元素個數達到閥值時:
首先小夥伴要明確:死迴圈問題在JDK 1.8 之前是存在的,JDK 1.8 通過增加loHead和loTail進行了修復。
在JDK 1.7及之前 HashMap在併發情況下導致迴圈問題,致使伺服器cpu飆升至100%,那麼今天就來解析一下執行緒不安全的HashMap在高併發的情況下是如何造成死迴圈的。
要探究hashmap死迴圈的原因 首先要知道hashmap的原始碼 這樣才能從根本上對hashmap進行理解 。
首先hashmap進行元素的插入,在元素個數達到閥值時:
addEntry對判斷桶有沒有達到閥值,達到閥值就會走resize方法:
resize方法裡呼叫transfer方法轉移元素:
下面這個方法就是出現死迴圈的方法了,下面請聽我一一道來:
新增元素達到閥值後對hashmap進行擴容,走reaize方法,在對hashmap進行擴容時,又會呼叫一個transfer對舊的hashmap中的元素進行轉移,那麼我們今天要探究的死迴圈問題 就是發生在這個方法裡的,在進行元素轉移時transfer方法裡會呼叫下面四行程式碼 :
Entry<k,v> next = e.next;
e.next = newTable[i];
newTable[i] = e;
e = next;
把元素插入新的hashmap中,粗略的看下這四行程式碼 似乎並沒有什麼問題 元素進行轉移的圖如下(執行緒不衝突的情況下):
那麼當多執行緒(A、B執行緒)同時訪問我們這段程式碼時:
現在A執行緒執行到以下程式碼時:
Entry<k,v> next = e.next;
執行緒A交出時間片,執行緒B這時候接手轉移並且完成了元素的轉移,這個時候執行緒A又拿到時間片並接著執行程式碼:
執行後代碼如圖,當e = a時,這時候這時候再執行:
e.next = newTable[i];// a元素指向了b元素 產生迴圈
這樣連結串列就就產生了迴圈,在get元素的時候,執行緒會一直在環了遍歷,無法跳出,從而導致cpu飆升!
總結:在多執行緒情況下儘量不要用HashMap,可以用ConcurrentHashMap代替。
大量面試經驗以及學習資料書籍請關注微信公眾號:**AVAJ**
回覆"offer"進行獲取
**365篇大廠java面經** 你想要的我這裡