一步一步學J2SE-ConcurrentHashMap原理
ConcurrentHshMap的數據結構是由一個Segment數組和多個HashEntry數組組成,在Segement數組中包含了HashEntry數組。數據結構如下圖所示:
Segement數組的意義就是將一個大的table分割成多個小的table來加鎖,而每一個Segment元素存儲的是HashEntry數組+鏈表,這個和HashMap的數據存儲結構一樣。
Put操作
當執行put操作的時候,會進行第一次key的hash來定位Segement的位置,如該Segement還沒有進行初始化,即通過CAS操作進行賦值,然後進行第二次hash操作,找到相應的HashEntry的位置,這裏會利用繼承過來的鎖的特性,在將數據插入HashEntry位置時,會通過繼承ReentrantLock的tryLock()方法嘗試獲取鎖,如果獲取成功就直接插入相應的位置,如果已經有線程獲取該Segment的鎖,那當前線程會以自旋的方式去繼續調用tryLock()方法去獲取鎖,超過指定次數就掛起,等待喚醒。
Get操作
ConcurrentHashMap的get操作跟HashMap類似,知識ConcurrentHashMap第一次需要經過一次hash定位到Segment的位置,然後再hash定位到指定過的HashEntry,遍歷該HashEntry下的鏈表進行對比,成功就返回,不成功就返回null。
Size操作
因為ConcurrentHashMap的元素大小是並發操作的,就是在計算size的時候,他還在並發插入數據,這可能會導致計算出來的size和實際的size不對應。Jdk1.7對這種情況有兩種解決方案
1、 它會使用不加鎖的模式去嘗試多次計算ConcurrentHashMap的size,最多三次,比較前面兩次計算的結果,結果一致就認為當前沒有元素加入,計算的結果時準確的。
2、 如果第一種方案不符合,就會對每個Segment加鎖,然後計算ConcurrentHashMap的size返回。
叠代操作
ConcurrentHashMap的遍歷時從後向前遍歷的,因為如果有另一個線程B正在執行clear操作時,會把table中的所有slot都置為null,這個操作時從前向後執行的,如果線程A在遍歷Map時也從前往後,就有可能出現追趕現象。
一步一步學J2SE-ConcurrentHashMap原理