1. 程式人生 > >HashMap,ConcurrentHashMap 原理分析

HashMap,ConcurrentHashMap 原理分析

帶環鏈表 原理 擴展 安全 nbsp adf java 線程 cit

----基於Java1.7的

HashMap原理

1.基於哈希原理,存儲key-value鍵值對(Entry)的集合。在JDK1.8以前數據結構是一個數組+鏈表,在JDK1.8以後是一個數組+鏈表+紅黑樹。(key,value,hash,next)

2.put方法原理:1)通過哈希函數計算key,得到哈希值;通過哈希值以及數組的長度,得到Entry的位置,即table的下標。index = HashCode(Key) & (Length - 1)

2)遍歷此下標下的鏈表,如果不存在相同key,即添加新的Entry,否則更新value值。

3.get方法原理:1)通過哈希函數計算key,得到哈希值;通過哈希值以及數組的長度,得到Entry的位置,即數組的下標。

2)遍歷此下標下的鏈表,如果存在相同key,即返回Entry。

4.在鏈表上插入新的Entry時,使用的是頭插法,因為hashMap的發明者認為,後插入的被查找的可能性比較大。

5.默認初始長度是16,每次擴展,必須是2的冪次方,理由是:為了服務於從key映射到index的哈希算法。

6.在插入元素過多時,需要進行resize,resize條件是HashMap.Size >= Capacity * LoadFactor。

7.resize方法原理:1)擴容--創建一個新的Entry數組,長度是原數組的兩倍

2)transfer方法--遍歷原Entry數組,把所有的Entry重新Hash到新數組。為什麽要重新Hash呢?因為長度擴大以後,Hash的規則也隨之改變。

8.非線程安全,在並發插入時,有可能出現帶環鏈表,讓下一次讀操作,進入死循環。

ConcurrentHashMap原理

1.ConcurrentHashMap是一個二級哈希表。在一個總的哈希表下面,有若幹個子哈希表。

2.采用了鎖分段技術,每個Segment各自持有一把鎖。在保證線程安全的同時降低了鎖的粒度,讓並發操作效率更高。

3.不同Segment的寫入是可以並發執行的。同一Segment的寫和讀是可以並發執行的。

4.put方法原理:1)通過key計算哈希值

2)通過哈希值,定位到segment。

3)獲取segment鎖

4)再次通過哈希值,定位到segment中數組的具體位置

5)插入或覆蓋hashEntry對象

6)釋放鎖

5.get方法原理:1)通過key得到哈希值

2)通過哈希值,定位到segment。

2)再次通過哈希值,定位到segment數組中具體位置

6.如何保證調用size方法時的一致性問題:1)判斷所有的segment總修改次數是否大於上一次統計的總修改次數,如果大於,說明有修改,重新統計。

2)如果嘗試次數超過閾值,則對每一個Segment加鎖,再重新統計。

為了盡量不鎖住所有Segment,首先樂觀地假設Size過程中不會有修改。當嘗試一定次數,才無奈轉為悲觀鎖,鎖住所有Segment保證強一致性。

HashMap,ConcurrentHashMap 原理分析