ConcurrentHashMap 源码分析
2021-05-27 19:27:44 21 举报
null
作者其他创作
大纲/内容
initTable
红黑树旋转时锁住红黑树的根节点保证同一时刻只有一个线程对红黑树进行旋转
否
拷贝 Node 时put 是否是转移结点
ConcurrentHashMap
发现是转移节点就会通过自旋等待,一直等到扩容完成后再进行新增
检查数组是否为空
直接返回
当前节点是否为空
通过 CAS 创建,失败继续自旋直至成功
get(Obj key)
SIZECTL 为 -1 表示当前只有一个线程能进行初始化
相同点:1、数组和链表结构相同,相关实现方法的思想也相同2、都继承了 AbstractMap 方法实现也大都相同,HashMap 有的方法 CHM 都有
是
CHM 和 HashMap
不同点:1、红黑树的实现节点不同,CHM 里面的红黑树不仅靠 TreeNode 实现,还靠 TreeBin 实现。在 HashMap 中 TreeNode 维护了红黑树的结构和功能,比如扩容、新增等;在 CHM 中TreeNode 维护了红黑树的属性和查找功能,TreeBin 维护了红黑树的其他功能2、新增了 ForwardingNode (转移节点),它为了保证扩容时的线程安全
判断根节点 Node 是否和 key 相等
1、如果是红黑树或转移节点,使用对应的 find 方法2、如果是链表遍历查找
当前是否是转移节点
拷贝完成后将 nextTab(新数组) 直接赋值给 table(数组容器)
transfer
进行 check 需不需要扩容,若需要即扩容
需要进行初始化
判断数组是否为空
1、多线程条件下同时进行 put、remove 并不会阻塞2、迭代过程中,即使 Map 的结构被改变,也不会出现 ConcurrentModificationException3、和 HashMap 相比,新增了转移节点:为了保证扩容时线程安全的节点4、大量使用 Stream 流式方法
先锁定当前 Node,保证其余线程不能操作
按链表和红黑树的方法进行新增
通过 key 的 hashcode 获取数组的下标
通过 CAS 自增
创建新的空数组,数组大小为原数组的两倍
锁住原数组当前 Node,成功拷贝到新数组时把原数组 Node 赋值成转移节点
新增 Node 值
putVal
锁定当前节点
while/for 自旋保证一定可以初始化/新增成功
检查当前 Node 是否有值
再次判断当前数组数组是否为空
将原数组元素全部拷贝到新数组(从队尾开始拷贝)
通过 CAS 设置 SIZECTL 的值来保证同一时刻只有一个线程进行初始化
putVal 时的线程安全
一直自旋,等待扩容完成之后再新增
收藏
0 条评论
下一页