ConcurrentHashMap数据结构在JDK1.7中的实现是二维数组加链表的结构,下面是画出来的鸟瞰图。数组
列出来的都是些重要参数,影响了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;
这里就列出几个有表明性的方法,不涉及到过多的细节,主要想学习设计思路。在讲代码的时候会隐藏掉一些细节,并用注释代替这段代码的做用,大部分状况下均可以忽略它的做用,尽可能让你们把更多的注意力放在主要代码上。数据结构
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 位置多线程
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); }
有时间再接着写把。。。。。。。。。。。并发