一.層次圖
image.png
二.結(jié)構(gòu)
- 參數(shù)
static final int DEFAULT_INITIAL_CAPACITY = 16;//容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;//擴(kuò)容因子
static final int DEFAULT_CONCURRENCY_LEVEL = 16;//并發(fā)度,程序運(yùn)行時(shí)能夠同時(shí)更新且不產(chǎn)生鎖競(jìng)爭(zhēng)的最大線程數(shù)
private transient final int hashSeed = randomHashSeed(this)//0;
- 結(jié)構(gòu)
//hash表分段集合
final Segment<K,V>[] segments;
//Segment(桶)
static final class Segment<K,V> extends ReentrantLock implements Serializable {
transient volatile HashEntry<K,V>[] table;
transient int count;
transient int modCount;
transient int threshold(capacity *loadFactor);
final float loadFactor;
}
//HashEntry(節(jié)點(diǎn))(數(shù)組加鏈表)
static final class HashEntry<K,V> {
final int hash;
final K key;
volatile V value;
volatile HashEntry<K,V> next;
}
- 初始化
ConcurrentHashMap初始化時(shí)枢步,計(jì)算出Segment數(shù)組的大小ssize和每個(gè)Segment中HashEntry數(shù)組的大小cap缚去,并初始化Segment數(shù)組的第一個(gè)元素;其中ssize大小為2的冪次方,默認(rèn)為16,cap大小也是2的冪次方,最小值為2净响,計(jì)算過(guò)程如下:
public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
int ssize = 1;
while (ssize < concurrencyLevel) {
++sshift;
ssize <<= 1;
}
......
int c = initialCapacity / ssize;
if (c * ssize < initialCapacity)
++c;
int cap = MIN_SEGMENT_TABLE_CAPACITY;//2
while (cap < c)
cap <<= 1;//<<1相當(dāng)于*2
Segment<K,V> s0 = new Segment<K,V>(loadFactor, (int)(cap * loadFactor),(HashEntry<K,V>[])new HashEntry[cap]);
Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
this.segments = ss;
}
image.png
三.加鎖機(jī)制
- 它與HashTable 使用synchronized對(duì)整個(gè)容器加鎖不同,ConcurrentHashMap可以做到進(jìn)行讀操作時(shí)不用加鎖喳瓣,進(jìn)行寫(xiě)操作的時(shí)候只需要鎖住對(duì)應(yīng)分段的哈希桶即可馋贤,而不用對(duì)整個(gè)容器加鎖。
- put加鎖
//根據(jù)key的hash找到對(duì)應(yīng)的Segment執(zhí)行put方法
public V put(K key, V value) {
Segment<K,V> s;
...
return s.put(key, hash, value, false);
}
final V put(K key, int hash, V value, boolean onlyIfAbsent) {
HashEntry<K,V> node = tryLock() ? null :
scanAndLockForPut(key, hash, value);
V oldValue;
.....
} finally {
unlock();
}
return oldValue;
}