【Java并发】ConcurrentHashMap原理

HashTale与ConcurrentHashMap 

  • Hashtable与ConcurrentHashMap都是线程安全的集合

  • Hashtable并发度低,整个Hashtable对应一把锁,同一时刻,只能有一个线程操作它

  • 1.8之前ConcurrentHashMap使用了Segment+数组+链表的结构,每个Segment对应一把锁,如果多个线程访问不同的Segment,则不会冲突

  • 1.8之后ConcurrentHashMap将数组的每个头节点作为锁,如果多个线程访问的头节点不同,则不会冲突

一、7的ConcurrentHashMap?

capacity:容量、factor:扩容因子、clevel:并发度

1)并发度

1.8之前ConcurrentHashMap使用了Segment+数组+链表的结构,每个Segment对应一把锁,并发度clevel就是Segment数组的容量(图中蓝色数组)。

每个Segment数组中存放数据个数:capacity/clevel,如果capacity <= clevel 那么存放数据个数默认为2(图中绿色数组)。

factor扩容因子是针对绿色数组的。

2)Segment索引计算

根据原始hash值,计算出二次hash值,根据Segment数组容量32->2^5,取二次hash值的高五位,来计算Segment下标

根据二次hash值的最低位来计算出桶下标

如下图:线程-1>>>  高四位(Segment下标):1100->12,最低位(桶下标):0

 

3)扩容

当超过( capacity/clevel )*factor时,扩容为原来的两倍,扩容操作在Segment数组中互不干扰

变化为

4)以Segment[0]为原型

每个Segment数组元素中的hashEntry小数组容量,以Segment[0]为原型来创建

(segment[0] 与 segment[4])

二、7与8的ConcurrentHashMap比较?

1)数据结构不同

        7的ConcurrentHashMap使用的是Segment+数组+链表,而8版本使用的是数组+链表|红黑树

2)创建时间不同

        7版本是饿汉式的初始化,而8版本是put数据时创建数组、是懒汉式的初始化

3)扩容时机不同

        7版本是超过3/4(capacity/factor)进行扩容,而8版本是到达3/4(capacity/factor)时进行扩容

三、8的ConcurrentHashMap?

capacity:要存放数据的个数、factor:扩容因子(调用构造方法时才用到)

1)并发put

因为8版本的ConcurrentHashMap是在链表头上加锁,如果多个线程操作的是同一个索引,则会阻塞(线程-2 与 线程-3)。

设置线程-2暂停时间10s,线程-2与线程-3都往10索引下加入数据,因为线程-2先获得表头锁,所以当线程-2睡眠时,线程-3执行不了,会进入阻塞状态。

多个线程操作多个索引,因为锁加在每个索引的链表头部,所以操作不会阻塞,提升了并发性能(线程-2 与 线程-4)。

线程-2 虽然睡眠10s,但是线程-4操作的索引为4,两个线程之间不共用一把锁,操作不会阻塞。

2)扩容

容量到达3/4(capacity/factor)时进行扩容

细节:

① 当扩容时其它线程进行get()操作:

当数组扩容时,会对已经扩容的索引位置标记。

1. 当其它线程进行get()操作时,首先会判断该索引位置是否已经被转移到另一个table中。如果已经被转移(链表头部被标记--图中F部分),则到新的table中查找,

2. 反之则在原来的table中进行查找。

② 当扩容时其它线程进行put()操作:

当数组扩容时,会对已经扩容的索引位置标记。

当其它线程进行put()操作时,首先会判断该索引位置是否已经被转移到另一个table中。

1. 如果已经被转移,则不能进行put()操作,但是会帮忙分担前一部分的扩容工作。

        例:要put的位置是11,则该put线程会帮助扩容线程执行0-5部分的扩容

2. 如果刚要被转移,由于扩容操作会在链表头部加上锁,所以put()操作阻塞。

        例:要put的位置是10,由于扩容操作会在链表头部加上锁,所以put线程阻塞

3. 如果还没被转移,则可以并发执行put()操作。

        例:要put的位置是5,可以执行

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值