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
學習中~ ,後續補充~