首先小伙伴要明確:死循環問題在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面經** 你想要的我這里都有