七.线程同步容器-ConcurrentHashMap

一.层次图

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;
        }

推荐阅读:深入分析ConcurrentHashMap

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容