深入理解Java中的ConcurrentHashMap

深入理解Java中的ConcurrentHashMap整体架构JDK1.

大家好,欢迎来到IT知识分享网。

整体架构

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

深入理解Java中的ConcurrentHashMap

jdk1.7存储结构

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

深入理解Java中的ConcurrentHashMap

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对数组进行扩容,在扩容时采用多线程并发扩容实现,即多个线程对原始数组进行分片,每个线程负责一个分片的数据迁移,从整体上提升了扩容过程中的数据迁移效率。

深入理解Java中的ConcurrentHashMap

多线程并发扩容

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

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

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

深入理解Java中的ConcurrentHashMap

size计算元素个数

思想借鉴

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


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

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/50848.html

(0)
上一篇 2024-08-22 18:26
下一篇 2024-08-22 21:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信