1. 程式人生 > >HashMap併發下死迴圈問題解析

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面經** 你想要的我這裡