HashMap多線程下發生死循環的緣由

概述html


大神陳皓已經在疫苗:JAVA HASHMAP的死循環一文中詳細描述了HashMap多線程下產生死循環的緣由,我仔細研讀了這篇大做,作了一些筆記,加上本身的一些理解
整理出一些信息,發出來與你們交流交流。算法


HashMap存儲的數據結構shell


陳皓在Hash表數據結構這一節提到了HashMap的數據結構以及擴容問題,關於這一點我以前寫過的
HashMap的put和get方法原理HashMap擴容已經有詳細的描述了。數組


多線程rehash的時候如何形成閉環鏈表數據結構


rehash源代碼
多線程

這裏寫圖片描述
這裏寫圖片描述

這裏寫圖片描述
這裏寫圖片描述


正常的rehash過程併發


數據準備
在size=2的HashMap中按照順序添加5, 7, 3這三個key,假設按照mod 2的算法來計算元素數組下標,那麼key 5,7,3都會落在下標爲1的數組桶中(發生hash衝突),以下圖:
.net

這裏寫圖片描述
這裏寫圖片描述

把HashMap的size擴容爲4後,rehash的過程線程

注意,發生hash衝突的5,7,3雖然都是在同一個鏈表中,可是每一個元素都得走rehash的過程,由於HashMap擴容後,這幾個元素就未必都是在同一個鏈表中了3d

一、第一個是處理3這個key,先把key爲3這個元素的next設置爲空,並計算它在新數組中的下標,並存到新下標對應桶中,以下圖:

這裏寫圖片描述
這裏寫圖片描述

二、第二個是處理7這個key,按照上面的約定,在新數組中3和7這個兩個key仍是發生了hash衝突,那麼按照HashMap發生衝突的處理代碼,鏈表的第一個元素存儲的是最新插入的7,而後next指向3,以下圖:

這裏寫圖片描述
這裏寫圖片描述

三、第三個是處理5這個key,以下圖:

這裏寫圖片描述
這裏寫圖片描述

到這裏一次正常rehash過程走完了,最後三個key的存儲狀況以下圖:

這裏寫圖片描述
這裏寫圖片描述


併發下的rehash過程


當兩個併發線程thread1和thread2都同時進入到transfer時,也便是,恰好thread1和thread2都要對HashMap進行擴容,萬一這個時候thread1執行下面的代碼時,被線程調度器掛起了,而thread2則正常的把擴容的操做作完,以下圖:

這裏寫圖片描述
這裏寫圖片描述

那這個時候,容器的數據存儲狀況以下:
對於thread1
這裏寫圖片描述
這裏寫圖片描述

對於thread2

這裏寫圖片描述
這裏寫圖片描述

這個時候,thread1擁有執行權限了,則繼續它的擴容操做,等thread1擴容完後就產生了一個環形鏈表了(注意這裏省略了一些步驟,不太明白的,則能夠看我以前寫的HashMap的put和get方法原理HashMap擴容)

這裏寫圖片描述
這裏寫圖片描述

這個時候,若是有個get請求,就有可能發生死循環,一直在鏈表中繞來繞去的,無法終止。


原文連接


HashMap多線程下發生死循環的緣由

相關文章
相關標籤/搜索