讲清楚ConcurrentHashMap(JDK 1.7)

1、ConcurrentHashMap 鸟瞰图
一、数据结构

ConcurrentHashMap数据结构在JDK1.7中的实现是二维数组加链表的结构,下面是画出来的鸟瞰图。数组

ConcurrentHashMap鸟瞰图

  1. 第一个红色标记segments数组初始长度是16(如何肯定的后面会提到),同时也是ConcurrentHashMap理想状态下最大的线程并发数。强调一点,segments是final的因此数组长度在初始化之后是不能改变的。
  2. 第二个红色标记HashEntry数组初始化长度是2(如何肯定的后面会提到),这也是ConcurrentHashMap实际存储数据的类。经过造成链表在同一个位置上存放多个数据。
  3. 第三个红色标记ReentrantLock是segment的父类,提供锁的功能,是ConcurrentHashMap保证线程安全的关键。从鸟瞰图能够看出,锁住的是单独的一个segment,只要多线程状况下,不是定位到同一个segment就不会形成线程冲突,从而提升多线程的执行效率。
二、属性

列出来的都是些重要参数,影响了ConcurrentHashMap的初始容量、扩容因子、默认的线程并发量、尝试次数等等安全

//默认容量。这里须要说明下,跟HashMap的做用不同,它不是直接控制HashEntry的容量,而是经过运行间接的得出。
static final int DEFAULT_INITIAL_CAPACITY = 16;
//负载因子。
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//默认并发等级。控制segments数组的长度,即ConcurrentHashMap的最大线程并发量。
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
//尝试次数。某些方法,例如size()等,会用到。具体做用是方法运行到指定次数之后还不是预期的结果就对方法进行加锁,再运行。
static final int RETRIES_BEFORE_LOCK = 2;
三、方法

这里就列出几个有表明性的方法,不涉及到过多的细节,主要想学习设计思路。在讲代码的时候会隐藏掉一些细节,并用注释代替这段代码的做用,大部分状况下均可以忽略它的做用,尽可能让你们把更多的注意力放在主要代码上。数据结构

  1. ConcurrentHashMap构造方法
public ConcurrentHashMap(int initialCapacity,
                             float loadFactor, int concurrencyLevel) {
        code_1 //三个参数都必须大于0,不然抛出异常。
        code_2 //concurrencyLevel大于65536时,设为65536
        // Find power-of-two sizes best matching arguments
        int sshift = 0;//这个不不知道意义是啥
        int ssize = 1;//segments数组长度。
        //每次循环至关于 ssize = 2^n,默认concurrencyLevel=16,那么ssize=16,sshift=4
        while (ssize < concurrencyLevel) {
            ++sshift;
            ssize <<= 1;
        }
        //这两个参数的做用后面会提到
        this.segmentShift = 32 - sshift;
        this.segmentMask = ssize - 1;
        code_3 //initialCapacity大于1073741824 时,设为1073741824
        code_4 //必定的运算得出 cap,这里只讨论 cap=2的默认状况。感兴趣的能够本身看源码
        int cap = MIN_SEGMENT_TABLE_CAPACITY;
        //建立 segment[]和初始化segment[0],segment[0]的做用给其余位置初始化时提供参数。
        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];
        UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
        this.segments = ss;
    }

总结来讲构方法作的就时建立segments[]和初始化 0 位置多线程

  1. put方法
ConcurrentHashMap的
 public V put(K key, V value) {
        Segment<K,V> s;
        code_1// value不能为空,不然异常
        code_2// 计算key在segments的下标
        int j = XX;
        if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
             (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
            //若是为空就初始化
            s = ensureSegment(j);
               //使用segment的
        return s.put(key, hash, value, false);
    }

有时间再接着写把。。。。。。。。。。。并发

相关文章
相关标签/搜索