ConcurrentHashMap(jdk7)

ConcurrentHashMap的UML结构如下
在这里插入图片描述
数据结构如下
在这里插入图片描述
ConcurrentHashMap内部维持一个Segment数组,存储一组锁,每个锁里面含有一个HashEntry数组,存取数据时先经过哈希算法判断出属于哪个锁管理,拿到锁后就进入了数据区,HashEntry对象是一个链表节点,相当于每个锁管理一个HashMap对象,由于此时操作都有锁保护,故ConcurrentHashMap相当于管理了多个线程安全的HashMap对象
下面来看下ConcurrentHashMap的主要源码

ConcurrentHashMap初始化
ConcurrentHashMap有5个构造函数,但其中4个最终调用的是第一个参数最多的构造函数,最后一个跟无参构造函数相比就多了一步putAll方法初始化了一组数据
在这里插入图片描述
看下第一个构造函数源码

	public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
	//如果加载因子小于0或者初始化容量小于0或者并发级别小于0  就抛出非法参数异常
        if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
            throw new IllegalArgumentException();
         //如果锁的数量大于最大分段数  就将锁的数量设置为最大分段数
        //MAX_SEGMENTS 为1<<16=65536,也就是最大并发数为65536
        if (concurrencyLevel > MAX_SEGMENTS)
            concurrencyLevel = MAX_SEGMENTS;
        //变量sshift用于记录ssize增加的次数
        // //2的sshif次方等于ssize,例:ssize=16,sshift=4;ssize=32,sshif=5
        int sshift = 0;
        变量ssize用于记录小于锁的数量的最大偶数
        int ssize = 1;
        while (ssize < concurrencyLevel) {
        //sshift增加1,
            ++sshift;
            //ssize扩大为原来的2倍
            ssize <<= 1;
        }
        //散列运算的位数
        this.segmentShift = 32 - sshift;
        //散列运算的掩码
        this.segmentMask = ssize - 1;
        //如果初始化容量大于最大容量  那么就设置初始化容量为最大容量
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        //计算cap的大小,即Segment中HashEntry的数组长度,cap也一定为2的n次方.
        //如果初始化容量大于最大容量  那么就设置初始化容量为最大容量
        int c = initialCapacity / ssize;
        /* 如果initialCapacity/ssize能整除
		 * 那么c*ssize =initialCapacity
		 * 如果initialCapacity/ssize不能整除有余数
		 * 那么就将分段数+1
		 * 获取最小分段数量 即每个分段锁可控制的元素数组最大长度
		 */
        if (c * ssize < initialCapacity) 
            ++c;
        // 默认 MIN_SEGMENT_TABLE_CAPACITY 是 2,这个值也是有讲究的,因为这样的话,对于具体的槽上,
    	// 插入一个元素不至于扩容,插入第二个的时候才会扩容
        int cap = MIN_SEGMENT_TABLE_CAPACITY;
        while (cap < c)
            cap <<= 1;
        // //创建segments数组并初始化第一个Segment,其余的Segment延迟初始化
        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];
        // 往数组写入 segment[0]
        UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
        this.segments = ss;
    }

对象初始化后,开始插入对象

	 public V put(K key, V value) {
        Segment<K,V> s;
        //concurrentHashMap不允许value为空
        if (value == null)
            throw new NullPointerException();
         //hash函数对key的hashCode重新散列,避免不合理的hashcode,保证散列均匀
        int hash = hash(key);
        //hash 是 32 位,无符号右移 segmentShift(28) 位,剩下高 4 位,
        // 然后和 segmentMask(15) 做一次与操作,也就是说 j 是 hash 值的高 4 位,也就是槽的数组下标
        // hash值是随机的 再跟15与操作  结果必然是0-15之间的一个数  保证了随机选取数组下标   
        int j = (hash >>> segmentShift) & segmentMask;
        //
        if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
             (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
            s = ensureSegment(j);
        return s.put(key, hash, value, false);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值