一、ConcurrentHashMap是什麼?
ConcurrentHashMap是線程安全的併發容器,是用來替代在多線程環境下的HashMap,因爲HashMap是線程不安全的,多線程環境下put操作可能會導致死循環,CPU利用率上升到100%。雖然有同步容器Hashtable和Collections.synchronizedMap方法使得容器同步,但是這些容器效率都非常低,因爲它們鎖的是整個容器,而ConcurrentHashMap採用的是分段鎖,將同一個容器的劃分爲好多段,某個線程執行某些操作只會獲取一個段的鎖,而不會影響其他線程獲取其他鎖的段。
二、ConcurrentHashMap的結構。
ConcurrentHashMap把整個容器很爲許多個Segment(段),段數就是併發度,每個Segment類似於一個Hashtable,管理一個HashEntry數組,每個HashEntry是一個鏈表頭,或者紅黑樹的根,其實Segment的數據結構類似於HashMap,學過HashMap的底層原理就更加容易理解ConcurrentHashMap,HashMap原理講解鏈接點擊打開鏈接。
分段鎖具體體現在哪裏?
Segment繼承ReentrantLock,這樣就很容易對每個Segment加鎖了。類似於get或remove這些操作,都只需要在操作前對一個Segment加鎖。但是有些操作需要跨段,比如size()、containsValue()和isEmpty()方法,因此爲了保證併發效率,允許size返回的是一個近似值而不是精確值。ConcurrentHashMap提供的迭代器不會拋出ConcurrentModificationException,因此不需要在迭代過程中對容器加鎖。即迭代器具有弱一致性,而非及時失敗。弱一致性的迭代器可以容忍併發的修改,當創建迭代器時會遍歷已有的元素,可以但不保證在迭代器被構造後將修改操作反映給容器。
(圖片來自網絡)
三、核心操作
1、哈希定位操作。
(1)首先對key進行hash運算,得到的值爲h1。即h1 = hash(key)。
(2)對h1的高几位進行hash操作,得到的值幾位Segment所在的位置。h2 = hash(h1高位)
(3)對h1進行hash操作,得到的值即爲該Segment中HashEntry所在的位置。h3 = hash(h1)
2、size()操作。
(1)在不對任何Segment加鎖的情況下,遍歷每個Segment,並且求和,如果三次中有相鄰兩次求得的每個Segment都相等,那麼說明在這兩次期間,每個Segment都沒有被更新,那麼可以直接返回size。
(2)若三次都不相等,那麼就全部加鎖,求和。
四、注意
1、key和value都不能爲null。
2、雖然ConcurrentHashMap是線程安全的,但不保證所有操作都是線程安全的