簡介
與ConcurrentHashMap類似的Java Conllections還有Hashtable和HashMap罩润,HashMap不是一個(gè)線程安全的類猜旬,key和value的值都可以是null沉眶,ConcurrentHashMap和HashMap都是線程安全的類球匕,但是key和value的值都不能是null。Hashtable保證線程安全的做法是每個(gè)可調(diào)用的方法都是synchronized的施掏。這意味著每個(gè)線程訪問Hashtable時(shí)都會(huì)把整個(gè)Hashtable鎖起來层宫。
> HashMap和HashTable的結(jié)構(gòu)圖:
??根據(jù)上圖可以看出同步的Hash容器是同步使用鎖來保證的,并且所有同步操作使用的是同一個(gè)鎖對象其监。這樣若有n個(gè)線程同時(shí)在get時(shí),這n個(gè)線程要串行的等待來獲取鎖限匣。(效率很低!)
ConcurrentHashMap則采用了分段鎖(Segment)的機(jī)制抖苦,使得競態(tài)條件只發(fā)生在Segment內(nèi)毁菱,增加了并發(fā)度;同時(shí)锌历,在HashMap.Entry的基礎(chǔ)上進(jìn)行改進(jìn)贮庞,ConcurrentHashMap.Entry的value和next域都是volatile的,可以保證在多線程環(huán)境下對于其他線程的可見性究西。由于ConcurrentHashMap不是對整個(gè)表加鎖窗慎,在執(zhí)行size()這些全局性質(zhì)的方法時(shí)需要遍歷整個(gè)Segment數(shù)組。
ConcurrentHashMap 的結(jié)構(gòu)分析
為了更好的理解 ConcurrentHashMap 高并發(fā)的具體實(shí)現(xiàn)卤材,讓我們先探索它的結(jié)構(gòu)模型遮斥。
??ConcurrentHashMap 類中包含兩個(gè)靜態(tài)內(nèi)部類 HashEntry 和 Segment。HashEntry 用來封裝映射表的鍵 / 值對扇丛;Segment 用來充當(dāng)鎖的角色术吗,每個(gè) Segment 對象守護(hù)整個(gè)散列映射表的若干個(gè)桶。每個(gè)桶是由若干個(gè) HashEntry 對象鏈接起來的鏈表帆精。一個(gè) ConcurrentHashMap 實(shí)例中包含由若干個(gè) Segment 對象組成的數(shù)組较屿。
HashEntry 類
HashEntry 用來封裝散列映射表中的鍵值對,在 HashEntry 類中,key卓练,hash 和 next 域都被聲明為 final 型隘蝎,value 域被聲明為 volatile 型。
<pre><code>static final class HashEntry<K, V> {
final int hash;
final K key;
volatile V value;
volatile HashEntry<K, V> next;
}</code></pre>
Segment 類
Segment 類繼承于 ReentrantLock 類襟企,從而使得 Segment 對象能充當(dāng)鎖的角色嘱么。每個(gè) Segment 對象用來守護(hù)其(成員對象 table 中)包含的若干個(gè)桶。
table 是一個(gè)由 HashEntry 對象組成的數(shù)組整吆。table 數(shù)組的每一個(gè)數(shù)組成員就是散列映射表的一個(gè)桶拱撵。
count 變量是一個(gè)計(jì)數(shù)器,它表示每個(gè) Segment 對象管理的 table 數(shù)組(若干個(gè) HashEntry 組成的鏈表)包含的 HashEntry 對象的個(gè)數(shù)表蝙。每一個(gè) Segment 對象都有一個(gè) count 對象來表示本 Segment 中包含的 HashEntry 對象的總數(shù)拴测。注意,之所以在每個(gè) Segment 對象中包含一個(gè)計(jì)數(shù)器府蛇,而不是在 ConcurrentHashMap 中使用全局的計(jì)數(shù)器集索,是為了避免出現(xiàn)“熱點(diǎn)域”而影響 ConcurrentHashMap 的并發(fā)性。
Segment 類的定義:
<pre><code>static final class Segment<K, V> extends ReentrantLock implements Serializable {
//在本 segment 范圍內(nèi)汇跨,包含的 HashEntry 元素的個(gè)數(shù)
transient volatile int count;
//table 被更新的次數(shù)
transient int modCount;
//當(dāng) table 中包含的 HashEntry 元素的個(gè)數(shù)超過本變量值時(shí),觸發(fā) table 的再散列resize
transient int threshold;
//裝載因子
final float loadFactor;
//table 是由 HashEntry 對象組成的數(shù)組
transient volatile HashEntry<K,V>[] table;
}
</code></pre>