自学内容网 自学内容网

ConcurrentHashMap解析

ConcurrentHashMap的结构

在这里插入图片描述

  • 实现了AbstractMap
  • 核心是有一个Segments的属性,这个属性相当于一个重入锁ReentrantLock,是一个数组加链表的结构,每个HashEntry数组进行修改时,必须获得它对应的Segment锁
  • 接着看表中Segments的属性中有一个HashEntry->这个是一个链表节点,用于存储数据,指向下一个节点(讲大数据分成几段数据,然后变成segment,每段数据当中又被分成多个数组)

初始化

通过三个属性:initCapcity ,concurrencyLevel,loadFactor
initCapcity
这个属性决定了ConcurrentHashMap的总初始容量,和之后的segment相关
concurrencyLevel
默认16,决定了segment的数量,最多支持16个线程并发写,一旦初始化,就不能再扩容
loadFactor
Segment中的哈希表使用的,refresh——>对哈希表(底层是数组)扩容

使用new ConcurrentHashMap()进行无参构造

  • 初始化容量Segment数组长度是16,不可以扩容
  • segment[i]的初始容量为2,loadFactor = 0.75

定位Segment

可以类比之前的HashMap,也是需要定位元素的
数据需要收到Segment分段锁保护,所以插入或者获取元素的时候,必须先定位到Segment
源代码
这个上面的就是源代码进行再散列,目的是减少散列冲突,使元素能够减少散列冲突,使元素均匀地分布在不同的Segment上,从而提高容器的存取效率。
在这里插入图片描述

get操作

在这里插入图片描述
先进行一次再散列,然后使用这个散列通过散列运算定位到Segment,再通过散列算法定位到元素。

get操作的高效之处在于这个get过程不需要加锁

put操作

这个必须加锁(写入)
在Segment里进行插入操作,插入操作需要经历两个步骤:

  • 是否需要扩容:在插入元素前会先判断Segment的HashEntry数组是否超过容量**(threshold)**,如果超出阈值,需要对数组进行扩容。Segment的扩容判断比HashMap更恰当
  • 定位添加元素的位置,然后将其放在HashEntry数组中。

size操作

连续不加锁累加2次,如果期间都发生了变化,再加锁:
使用modCount这个中间变量,对于添加,删除,修改这些操作都对modCount进行加1.

JDK 1.8ConccurrentHashmap实现原理

数组+链表 ->数组+链表+红黑树,加锁采用CAS和synchronized

get 方法

在这里插入图片描述

  • 计算Hash值,并由此找到槽点
  • 如果数组是空->返回null
  • 如果该位置节点是我们需要的,直接返回该节点的值
  • 如果改位置节点是红黑树或正在扩容,直接使用find继续查找
  • 否则就是链表,进行遍历链表查找

原文地址:https://blog.csdn.net/m0_74107946/article/details/141785081

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!