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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM