源码QA解析"/>
JDK1.7 ConcurrentHashMap源码QA解析
前面说到JDK1.7 HashMap是数组+链表的数据结构,但是这是线程不安全的。而ConcurrentHashMap则是HashMap的升级版解决了线程安全问题,而且底层大部分逻辑和HashMap是相似的。接下来还是通过QA方式解析源码。
1.ConcurrentHashMap的数据结构是怎么样的?初始化过程是怎么样的?
(1)首先,ConcurrentHashMap设计是作为线程安全的Map集合,那么就需要考虑怎么支持并发操作,我们用HashMap进行对比,就可以知道HashMap要想并发安全操作就不能不对整个HashMap进行加锁,这样大大影响了整个容器的性能。
作为解决这个问题的设计者们,在ConcurrentHashMap就想到了基于HashMap的数组+链表的思想,将每个数组都拆分成一个个小型各自独立的Segment(每个Segment相当于一个个小型HashMap),每个线程加锁只对各自独立的Segment去加锁操作,这样就大大提升了性能。于是就引入了“分段Segment”的思想,每个分段还集成了ReentrantLock可以对内部HashEntry数据进行CAS操作,这样就保证了线程安全。基于此,ConcurrentHashMap的数据结构图大致可以如下:
上图可知:在JDK7的ConcurrentHashMap中,首先有一个Segment数组,存的是Segment对象,Segment相当于一个小HashMap,而Segment内部有一个HashEntry的数组用于存储实际数据。
(2)ConcurrentHashMap有哪些核心属性,数据结构是怎么初始化的?
从上面知道ConcurrentHashMap与HashMap的属性相似,不同的是ConcurrentHashMap内部有一个Segment数组,而每个Segment内部存储HashEntry数组。
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>implements ConcurrentMap<K, V>, Serializable {//默认初始化容量大小16static final int DEFAULT_INITIAL_CAPACITY = 16;/*** 默认加载因子0.75*/static final float DEFAULT_LOAD_FACTOR = 0.75f;/*** Segment分段的数量,默认也是16个分段数*/static final int DEFAULT_CONCURRENCY_LEVEL = 16;/*** 最大容量数:2^30,保证所有元素可以存储不越界*/static final int MAXIMUM_CAPACITY = 1 << 30;/*** 每个Segment内部的HashMap数组最小长度:默认最小为2*/static final int MIN_SEGMENT_TABLE_CAPACITY = 2;/*** 每个Segment内部的HashMap数组最大长度:最大为2^16*/static final int MAX_SEGMENTS = 1 << 16;/*** 尝试非阻塞加锁次数,如果超过次数还没能加锁则转换为阻塞等待加锁*/static final int RETRIES_BEFORE_LOCK = 2;/*** hash种子,可影响hash散列*/private transient final int hashSeed = randomHashSeed(this);/*** 当前segments数组的最大下标*/final int segmentMask;/*** 32-(segments数组长度最大下标对应二进制最高位1开始往后占据的位数)* 例如20=0001 0100,则最高位1开始往后共占据5个位数,则segmentShift=32-5=27。* 相当于保留hash值的高n位,用于put操作对hash右移segmentShift位数,使hash的高n位* 算出要存在segments哪个位置。*/final int segmentShift;/*** 最核心的segment分段数组,是一个Segment对象*/final Segment<K,V>[] segments;
更多推荐
JDK1.7 ConcurrentHashMap源码QA解析
发布评论