天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

前言

師傅,我經常聽別人說,不要在併發狀況下使用HashMap,可能會出現死循環,這個死循環是怎麼造成的呢?面試

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

一塵數組

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

慧能數據結構

這個聽爲師慢慢道來併發

咱們都知道,HashMap的底層是由數組加鏈表來實現的ide

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

當往HashMap中put一個鍵值對時,若是HashMap中的鍵值對數量 size 大於或等於閾值(threshold) 而且null != table[bucketIndex] 時會進行擴容高併發

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

bucketIndex爲該鍵值對最後被散列到hash表table的位置學習

好比 table的初始容量爲4,加載因子爲0.75,此時閾值爲3,table已有三個元素,如今put一個元素<1,」A」>,<1,」A」>被散列到table[1]處,而table[1] != null,此時知足擴容條件線程

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

閾值 = 容量 * 加載因子3d

threshold = capacity * loadFactorblog

擴容時先生成一個是table大小2倍的newTable,而後把table中的元素遷移到newTable中,遷移的工做就由 transfer方法來完成,這個方法就是引發死循環的緣由所在

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

環的造成

如今咱們來模擬一下環是如何造成的,設HashMap的初始容量爲4,先往HashMap中依次put三個元素<5,」B」>、<9,」C」>、<1,」A」>,它們都被散列到table[1]處,造成了鏈

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

假設此時有兩個線程併發對該HashMap進行put,線程1 put <13,」D」>時,這個鍵值對被散列到table[1]處,知足擴容條件,進行擴容(生成newTable並進行遷移)

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

此時,線程1用 transfer 方法將 table中的元素遷移到 newTable 中,假設線程1執行完 transfer 方法中的 Entry<K,V> next = e.next 語句後時間片用完,掛起

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

此時,線程1內的 e 指向 <1,「A」>,next指向<9,」C」>

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

而後線程2 put <16,」E」>,一樣這個鍵值對被散列到table[1]處,知足擴容條件,進行擴容

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

生成完newTable後用transfer方法進行遷移,執行完Entry<K,V> next = e.next;後與線程1同樣,e指向<1,」A」>,next指向<9,」C」>

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

線程2 而後執行循環體下面的語句

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

線程2執行完以後爲下圖

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

而後線程2按照一樣的邏輯進行第二次循環(while循環),下面是第二遍循環後的結果

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

下面是第三遍循環後的結果

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

此時,線程2時間片用完,線程1獲得時間片,開始執行

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

注意,此時線程1的e指向<1,A>,next指向<9,C>,在線程2操做鏈表的時候,線程1 中的e,next指向的元素沒變(一直是紅色的e和next)

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

線程一和線程二總體圖爲:

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

而後線程1開始執行循環內剩下的代碼

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

執行完後爲下圖

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

線程1繼續執行第二遍循環

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

執行完爲下圖

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

線程1繼續第三遍循環(注意:這次循環會造成環)

先執行 Entry<K,V> next = <1,A>.next

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

而後執行 <1,A>.next = newTable[1]

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

此時環已經造成

而後執行剩餘的兩行代碼

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

執行完,e 爲 null,退出循環

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

死循環的發生

當造成環後,當給HashMap中put元素的時候,這個元素恰巧落在了table[1](無論有沒有更新table),而這個元素的Key不在table[1]這條鏈上,此時會發生死循環

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

或者在get元素的時候,該元素恰巧落在table[1]上,而且該元素的Key不在該鏈上,會發生死循環

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

原來死循環是這樣造成的

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

一塵

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

慧能

對,核心就是線程2修改了原來的鏈表結構,而線程1卻以原來的邏輯執行遷移

那併發下我還想使用散列表這種數據結構怎麼辦呢

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

一塵

天貓面試官:說說高併發下的HashMap的死循環是怎麼造成的!

慧能

用ConcurrentHashMap

今日份讀者福利:轉發+關注公衆號:麒麟改bug,獲取小編整理好的200多頁Java核心學習筆記一份!

最後

喜歡小編今日的分享,記得關注我點贊喲,感謝支持!重要的事情說三遍,轉發+轉發+轉發,必定要記得轉發 關注哦!!!

相關文章
相關標籤/搜索