Java | ConcurrentHashMap

Java7:

ConcurrentHashMap在內部細分爲若干個小的HashMap,叫做數據段Segment。默認情況下,一個ConcurrentHashMap被細分爲16個Segment,對每個Segment的數據都單獨進行加鎖操作。Segment的個數則爲鎖的併發度。

ConcurrentHashMap是由Segment數組和HashEntry數組組成的。Segment繼承了可重入鎖ReentrantLock,它在ConcurrentHashMap裏扮演鎖的角色。HashEntry則用於存儲鍵值對數據。

在每一個ConcurrentHashMap裏都包含一個Segment數組,Segment的結構和HashMap類似,是數組和鏈表結構。在每個Segment裏都包含一個HashEntry數組,每個HashEntry都是一個鏈表結構的數據,每個Segment都守護一個HashEntry數組裏的元素,在對HashEntry數組的數據進行修改時,必須首先獲得它對應的Segment鎖。

在操作ConcurrentHashMap時,如果需要在其中添加一個新的數據,則並不是將整個HashMap加鎖,而是先根據HashCode查詢該數據應該被存放在哪個Segment,然後對該Segment加鎖並完成put操作。在多線程併發情況下, 只要加入的數據被存放在不同的Segment中,線程間就可以做到並行的線程安全。

 

JDK8與JDK7中ConcurrentHashMap的區別:

多線程併發環境下鎖機制:

JDK7中ConcurrentHashMap主要對整個桶數組進行了分割分段即Segment,每一把鎖只鎖容器其中一部分數據,多線程訪問容器裏不同數據段的數據,就不會存在鎖競爭,提高併發訪問率。

JDK8中使用的是優化的synchronized 關鍵字同步代碼塊 和 CAS原子操作維護併發。

數據結構:

JDK7中ConcurrentHashMap使用使用 Segment數組 + HashEntry數組 + 鏈表。一個Segments數組,存儲一個Segments對象,一個Segments中儲存一個Entry數組,存儲的每個Entry對象又是一個鏈表頭結點。

數據結構:

而JDK8中使用 Node數組+鏈表+ 紅黑樹,Node數組使用來存放樹或者鏈表的頭結點,當一個鏈表中的數量到達一個數目時,會使查詢速率降低,所以到達一定閾值時,會將一個鏈表轉換爲一個紅黑二叉樹,通告查詢的速率。

 

 效率:

首先HashMap多線程環境下不安全。而Hashtable使用的是synchronized方法鎖,若一個線程搶奪了鎖,其他線程只能等到持鎖線程操作完成之後才能搶鎖操作。

對於ConcurrentHashMap:

JDK7中使用的分段鎖,只要加入的數據被存放在不同的Segment中,線程間就可以做到並行的線程安全。

JDK8中put()和get()不用二次哈希,一把鎖只鎖住一個鏈表或者一棵樹,併發效率更加提升。

 

 

實際上JDK8中ConcurrentHashMap已經不採用Segment鎖機制,雖然有內部類Segment,單實際上沒什麼作用。而是採用synchronized+CAS原子操作來確保併發的安全。

 

ConcurrentHashMap在JDK7與JDK8中的不同: 

https://blog.csdn.net/qq_41884976/article/details/89532816

https://www.jianshu.com/p/5dbaa6707017

 

學習中~ ,後續補充~ 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章