一.层次图
image.png二.结构
- 参数
static final int DEFAULT_INITIAL_CAPACITY = 16;//容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;//扩容因子
static final int DEFAULT_CONCURRENCY_LEVEL = 16;//并发度,程序运行时能够同时更新且不产生锁竞争的最大线程数
private transient final int hashSeed = randomHashSeed(this)//0;
- 结构
//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(节点)(数组加链表)
static final class HashEntry<K,V> {
final int hash;
final K key;
volatile V value;
volatile HashEntry<K,V> next;
}
- 初始化
ConcurrentHashMap初始化时,计算出Segment数组的大小ssize和每个Segment中HashEntry数组的大小cap,并初始化Segment数组的第一个元素;其中ssize大小为2的幂次方,默认为16,cap大小也是2的幂次方,最小值为2,计算过程如下:
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相当于*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
三.加锁机制
- 它与HashTable 使用synchronized对整个容器加锁不同,ConcurrentHashMap可以做到进行读操作时不用加锁,进行写操作的时候只需要锁住对应分段的哈希桶即可,而不用对整个容器加锁。
- put加锁
//根据key的hash找到对应的Segment执行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;
}
网友评论