快捷搜索:  汽车  科技

concurrenthashmap 底层实现原理(深入理解Java中的ConcurrentHashMap)

concurrenthashmap 底层实现原理(深入理解Java中的ConcurrentHashMap)寻址性能:引入红黑树降低了数据查询的时间复杂度从O(n)->O(logN)。锁粒度上:ConcurrentHashMap锁的粒度是数组中的一个节点(JDK1.7锁定的是Segment 粒度比较粗)。当初始化ConcurrentHashMap实例时,默认初始化一个长度16的数组,因为底层核心还是Hash表,必然存在Hash冲突的问题,所以它采用链式寻址的方式解决Hash冲突。当Hash冲突比较多时会造成链表长度较长,寻址性能下降,为了提高寻址性能,JDK1.8中引入了红黑树,当数组长度大于64并且链表长度大于等于8时,单向链表就会转化成红黑树。随着ConcurrentHashMap动态扩容,一旦链表的长度小于8时,红黑树就会退化成单向链表。ConcurrentHashMap的功能和HashMap一样,它在HashMap的基础上提供了并发安全的一个实现,并发安全的实现主要是通过对于Nod

整体架构

jdk1.7版本的存储如下图,采用Segment HashEntry的方式进行实现,每个Segment中包含一个与HashMap数据结构差不多的链表数组 理论上最大并发度与Segment个数相等,锁分段的思想提高了并发性,用ReentrantLock来保证并发安全;

concurrenthashmap 底层实现原理(深入理解Java中的ConcurrentHashMap)(1)

jdk1.7存储结构

JDK1.8版本的存储如下图,由数组,单向链表红黑数组成。为了进一步提高并发性 摒弃了分段锁方案 取而代之的是采用Node CAS Synchronized来保证并发安全,同时为了提高哈希碰撞下的寻址性能 在链表长度超过一定阈值(8)时将链表(寻址时间复杂度为O(N))转换为红黑树(寻址时间复杂度为O(log(N)))。

concurrenthashmap 底层实现原理(深入理解Java中的ConcurrentHashMap)(2)

jdk1.8中的存储结构

当初始化ConcurrentHashMap实例时,默认初始化一个长度16的数组,因为底层核心还是Hash表,必然存在Hash冲突的问题,所以它采用链式寻址的方式解决Hash冲突。当Hash冲突比较多时会造成链表长度较长,寻址性能下降,为了提高寻址性能,JDK1.8中引入了红黑树,当数组长度大于64并且链表长度大于等于8时,单向链表就会转化成红黑树。

随着ConcurrentHashMap动态扩容,一旦链表的长度小于8时,红黑树就会退化成单向链表。

基本功能

ConcurrentHashMap的功能和HashMap一样,它在HashMap的基础上提供了并发安全的一个实现,并发安全的实现主要是通过对于Node节点加锁来保证数据更新的安全性。

性能优化

锁粒度上:ConcurrentHashMap锁的粒度是数组中的一个节点(JDK1.7锁定的是Segment 粒度比较粗)。

寻址性能:引入红黑树降低了数据查询的时间复杂度从O(n)->O(logN)

多线程并发扩容:当数组的长度不够时,ConcurrentHashMap对数组进行扩容,在扩容时采用多线程并发扩容实现,即多个线程对原始数组进行分片,每个线程负责一个分片的数据迁移,从整体上提升了扩容过程中的数据迁移效率。

concurrenthashmap 底层实现原理(深入理解Java中的ConcurrentHashMap)(3)

多线程并发扩容

size方法优化:在多线程并发场景中实现元素个数累加性能非常低,ConcurrentHashMap做了两个点优化。

1.当线程竞争不激烈的时候,直接采用CAS的方式实现元素个数的原子递增。

2.当线程竞争激烈的时候,使用一个数组来维护元素个数,如果增加总的元素个数时候,直接从数组中随机选择一个,再通过CAS算法来实现原子递增。核心思想是引入数组来实现对并发更新的一个负载。

concurrenthashmap 底层实现原理(深入理解Java中的ConcurrentHashMap)(4)

size计算元素个数

思想借鉴

从ConcurrentHashMap实现上来看,有一些思想值得我们借鉴,例如:锁的粒度控制、分段锁的设计、采用无锁(CAS)方式、多线程并发扩容思想、冲突链表太长转换为红黑树等,这些经典思想平时也可以用于工作中的项目里。[赞]


喜欢就收藏吧,关注我更多有价值的文章会第一时间推荐给你![玫瑰][玫瑰][玫瑰]

猜您喜欢: