ConcurrentHashMap
2021-06-19 16:39:46 0 举报
源码流程解析
作者其他创作
大纲/内容
int sizeMask = newCapacity - 1; int idx = e.hash & sizeMask;
获取锁,获取不到,cas自旋获取锁,自旋的过程中检测遍历hashentry数组中有没有key相等的entry,没有的话新建一个enrty作为node节点放在entry列表的头部,自旋一定的次数没有获取到锁直接阻塞
结束
空指针异常
计算hash值,和segment的位置,查找segment
获取node,判断该位置是否为空
JDK1.8
判断值是否为空
判断node的hash是否==-1
头插法插入
更新tab index位置的node
判断节点是否为空
是
不断的自旋 tryLock() 获取锁。当自旋次数大于指定次数时,使用 lock() 阻塞获取锁。在自旋时顺表获取下 hash 位置的 HashEntry
该位置segment是否为空
获取hashentry
否
寻找lastRun节点,该节点后面的节点计算出老的在新数组的位置都一样都是一样
开始
cas设置值,跳出
判断该节点是否有下一个节点
c>thredload
直接把该节点设置到新数组idx的位置
跳出循环或者循环结束
计算该节点在新entry数组中的位置下标idx
计算hashentry的位置
在该segment设置值
设置值
计算node的位置
获取node数组
是的话,替换值
判断是否获取到锁,node!=null?
解锁
0.hashentry数组容量变为原来的2倍1. e.hash & sizeMask计算新的位置,新的位置只可能是不遍或者是老的位置+老的容量。 2.循环找出所有位置不变节点。3.循环头插入剩下的节点
根据entry数组下标获取entry下的链表
fh >= 0判断是链表
key相等,直接替换value
数据节点插入红黑树中
判断entry是否为null
1.检查该segment是否为空2.新建hashentry数组,3.再次检查该segment是否为空4.自旋检查该segment是否为空,为空就为segment设置阈值,加载因子,hashentry数组
JDK1.7
判断node数组是否为空
判断容量大于扩容阀值并且小于最大容量
循环遍历链表中的entry
binCount >= TREEIFY_THRESHOLD判断链表长度是否大于阈值8
判断entry的key是否相等
计算seg下entry的下标int index = (tab.length - 1) & hash;
以lastRun节点为界线,lastRun以及后面的放在lastRun节点在新数组tab的同一个下标位置上,前面的则重新计算hash
加入新的值或者覆盖旧值
直接把值放在node节点
转成红黑树
报空指针异常
自旋cas操作初始化Node数组
使用synchrized锁,设置值
初始化segment
f instanceof TreeBin判断是树
计算node的hash值
rehash扩容
初始化node数组
遍历hashentry的链表节点
再把新元素放到数组中
判断是否有节点是否为null
扩容
遍历oldEntry列表
将新链表赋值给table
1.计算新的entry数组容量,newCap=oldCap*2;2.计算阈值newThreaload=newCap*0.75;3.封装一个新的新的entry数组
ConcurrentHashMap的数据结构是怎样的?ConcurrentHashMap的容量为什么是2的整数次方?如何实现的并发安全?是读写分离吗?get需要加锁吗?哈希冲突体现在哪里,如何解决?扩容思想是什么,怎么扩容?int index=(hash >>> segmentShift) & segmentMaskinitialCapacity / ssize; cap<c cap>>1
收藏
收藏
0 条评论
下一页