concurrentHashMap实现原理

JDK6与JDK7中的实现:
理解concurrentHashMap首先最关键先理解一个概念:segment
segment是什么呢?segment本身就相当于一个HashMap对象,同时又继承了ReentrantLock;同HashMap一样,segment包含一个HashEntry数组,数组的每一个HashEntry既是一个键值对,也是一个链表的头节点;HashEntry中的value和next都被volatile修饰,用于多线程保证可见性。
像这样的segment对象,在concurrentHashMap中集合中有2的N次方个,共同保存在一个名为segments的数组当中。
 
因此整个ConcurrentHashMap的结构如下:
concurrentHashMap是在一个总的哈希表下面,有若干个子哈希表。这样的二级结构,数据库的水平拆分有些相似。
这样设计的优势在于:才用了锁分段技术,每一个segment就好比一个自治区,读写操作高度自治,segment之间互不影响。
不同segment的写入可以并发执行,同一个segment的读写可以并发执行,同一个segment的并发写会被阻塞。由此可见,concurrentHashMap当中每个segment各自持有一把锁。在保证线程安全的同时降低了锁的粒度,让并发操作效率更高。
ConcurrentHashMap的读写详细过程:
Get方法:
1.为输入的key做hash运算,得到hash值
2.通过hash值,定位到对应的segment对象
3.再次通过hash值,定位到segment当中数组的具体位置
Put方法:
1.为输入的key做Hash运算,得到hash值
2.通过hash值,定位到对应的segment对象
3.获取可重入锁
4.再次通过hash值,定位到segment当中的数组的具体位置
5.插入活覆盖hashEntity对象
6.释放锁
 
ConcurrentHashMap的size方法是一个嵌套循环,答题逻辑如下:
1.遍历所有segment
2.把segment的元素数量累加起来
3.再一次把segment的元素数量累加起来
4.判断这一次与上一次统计的是否一致,不一致,重新统计,尝试次数+1;如果不是,说明没有修改,统计结束
5.如果尝试次数超过了阈值,则对每一个segment加锁,再重新统计
6.再次判断所有segment的总修改次数是否大于上一次的总修改次数;由于已经加锁,次数一定和上次相等
7.释放锁,统计结束
 
ConcurrentHashMap在对Key求Hash值的时候,为了实现Segment均匀分布,进行了两次Hash。
 
并发度的概念:
  可以理解为:能够同时跟新ConcurrentHashMap且不产生锁竞争的最大线程数,实际上就是ConcurrentHashMap的分段锁个数,即Segment[]数组的长度。

rehash的概念:
    相对于HashMap的resize,ConcurrentHashMap的rehash原理类似,但是做了一定的优化,避免让所有的节点都进行复制操作:由于扩容是基于2的幂指来操作,假设扩容前某HashEntry对应到Segment中数组的index为i,数组的容量为capacity,那么扩容后该HashEntry对应到新数组中的index只可能为i或者i+capacity,因此大多数HashEntry节点在扩容前后index可以保持不变。基于此,rehash方法中会定位第一个后续所有节点在扩容后index都保持不变的节点,然后将这个节点之前的所有节点重排即可。

ConcurrentHashMap是弱一致性,get到的数据可能是过时的。ConcurrentHashMap不允许key或者value为null。

JDK8中的实现:

  摒弃了Segment分段锁的概念,启用了CAS算法,底层依然由 “数组” + 链表 + 红黑树的方式;为了并发,添加了例如:TreeBin、Traverser等内部对象类。

  sizeCtl属性:负值代表正在进行初始化或者扩容,-1代表正在初始化 ,-N代表有N-1个线程正在扩容;正数或者0代表hash表还没有被初始化,这个值标识初始化或者下一次扩容的大小,始终未ConcurrentHashMap容量的0.75倍,与loadfactor对应。

  不采用segment而采用node,锁住node来实现减小锁粒度。
  设计了MOVED状态 当resize的中过程中 线程2还在put数据,线程2会帮助resize。
  使用3个CAS操作来确保node的一些操作的原子性,这种方式代替了锁。
  sizeCtl的不同值来代表不同含义,起到了控制的作用。

 

posted @ 2019-10-29 16:44  兔老霸夏  阅读(616)  评论(0编辑  收藏  举报