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)!