ConcurrentHashMap详解

26 篇文章 0 订阅
13 篇文章 0 订阅

ConcurrentHashMap详解

HashTable和Vector是线程安全的(本质是Synchronized),其他的集合(ArrayList…)是通过Collections.synchronized*()系列的方法来实现线程安全操作,JDK1.5后提供了线程安全的容器,在Java.util.concurrent包路径下
在这里插入图片描述

通过继承图可知,线程安全的类在ConcurrentMap接口下,该接口有两个实现类:ConcurrentHashMap和ConcurrentSkipListMap
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上四个方法都是线程安全的操作

  • ConcurrentHashMap
    属性及默认值
//默认初始容量 16 
static final int DEFAULT_INITIAL_CAPACITY = 16;
//默认加载因子 0.75
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
//默认的并发度 16 ->segments数组的大小 
    static final int DEFAULT_CONCURRENCY_LEVEL = 16;
//容量的上限->segments数组的大小
    static final int MAXIMUM_CAPACITY = 1 << 30;
//Segment中HashEntry数组的最小值
    static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
//Segment的最大值,最大的并发度
    static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
//锁重入的次数
    static final int RETRIES_BEFORE_LOCK = 2;
//主要作用于keyhash过程
    final int segmentMask;
    final int segmentShift;
//存储数据节点的位置。Segment的数组
    final Segment<K,V>[] segments;

   //获取key对应集合
    transient Set<K> keySet;
//获取key-value键值对集合
    transient Set<Map.Entry<K,V>> entrySet;
//获取value的集合
    transient Collection<V> values;
        
 //segment的锁是ReentantLock锁的子类       
  static final class Segment<K,V> extends ReentrantLock implements Serializable {
        static final int MAX_SCAN_RETRIES =
            Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;

        //存放数据
        transient volatile HashEntry<K,V>[] table;
       //存放数据的个数
        transient int count;
        transient int modCount;
        transient int threshold;
        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用了16个Segment的结构(HashEntry的数组),每一个Segment又拥有一个独占锁,对同一个segment下的操作存在互斥(写是护指的,读存在并发),不同的segment之间是相互独立的,不存在并发的问题,也就是:ConcurrentHashMap下同一时刻至少可以是16个线程(默认并发度)进行并发操作

  • 构造函数
//通过初试容量、加载因子、并发度来创建ConcurrentHashMap实例
public ConcurrentHashMap(int initialCapacity,float loadFactor, int concurrencyLevel) {
    //对加载因子,初始容量,并发读的最小值做限制     
    if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
            throw new IllegalArgumentException();
       //并发读最大值做线程
        if (concurrencyLevel > MAX_SEGMENTS)
            concurrencyLevel = MAX_SEGMENTS;
        // Find power-of-two sizes best matching arguments
        //记录ssize的左移的次数
        int sshift = 0;
        //ssize的值是有concurrencyLevel类决定的,大小为大于concurrencyLevel的最小的2的N次方
        int ssize = 1;
       //concurrencyLevel=17,
     // 1< 17 sshfit =1, ssize=2;
     //2<17 sshfit=2,ssize=4
    //4<17 sshfit=3,ssize = 8
    //8<17 sshfit=4,ssize= 16
    //16<17 shhfit=5,ssize=32;
    //32<17 break  ssize = 32 ,sshfit=5
        while (ssize < concurrencyLevel) {
            ++sshift;
            ssize <<= 1;
        }
       //段偏移量
        this.segmentShift = 32 - sshift;
        //散列算法的掩码,默认情况segmentMask=15
        this.segmentMask = ssize - 1; //1111111->key的hash需要segmentMask
    //容量上限
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
      //c记录每个segment上要记录的元素
        int c = initialCapacity / ssize;
      //加入有余数,则Segment进行+1
        if (c * ssize < initialCapacity)
            ++c;
        int cap = MIN_SEGMENT_TABLE_CAPACITY;
        while (cap < c) //保证HashEntry数组是2的倍数
            cap <<= 1;
        // create segments and segments[0]
        Segment<K,V> s0 =new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
                             (HashEntry<K,V>[])new HashEntry[cap]);
    //创建ssize长度的Segment的数组,默认初始情况下是16
        Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
         //将所有的Segment进行初始化
        UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
        this.segments = ss;
    }


    public ConcurrentHashMap(int initialCapacity, float loadFactor) {
        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
    }


    public ConcurrentHashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
    }


    public ConcurrentHashMap() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
    }

 //通过集合来创建ConcurrentHashMap的实例
    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
                      DEFAULT_INITIAL_CAPACITY),
             DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
        putAll(m);
    }

本人才疏学浅,如有错误,烦请指出,谢谢!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值