《集合》之concurrentHashmap
JDK1.8 ConcurrentHashMap 采用的数据结构跟HashMap一样,数组+链表+红黑树;
摒弃了Segment的概念,通过 synchronized 、CAS 保证线程安全。
put操作
1)判断数组是否为空,为空进行初始化
2)不为空,则计算 key 的 hash 值,通过(n - 1) & hash计算哈希槽;
3)查看哈希槽是否存在数据,没有数据 CAS插入
4)存在数据,是否处于迁移状态,
是,协助迁移
不是,锁住该槽:插入元素、释放槽上的锁
5)需要将链表转红黑树:锁住该槽、构建红黑树替换链表、释放槽上的锁
6)插入完成之后判断当前节点数是否大于阈值,若大于,则扩容为原数组的二倍
Node节点
Node只有一个next指针,是一个单链表。
hash冲突,Node结点会首先以链表的形式链接到table上,当结点数量超过一定数目时,链表会转化为红黑树。
TreeNode节点
红黑树结点,TreeNode不会直接链接到table[i](哈希槽),由TreeBin链接,TreeBin会指向红黑树的根结点。
TreeBin节点
TreeBin会直接链接到table[i](哈希槽),该结点提供了一系列红黑树相关的操作,以及加锁、解锁操作。
另外TreeBin提供了一系列的操作
- TreeBin(TreeNode<K,V> b),链表转红黑树.
- lockRoot(),红黑树根结点加写锁
- unlockRoot(),释放写锁
- find(int h, Object k),从根结点开始遍历查找。
ForwardingNode
ForwardingNode 在table扩容时使用,内部记录了扩容后的table。
扩容时,依次遍历table中的每个槽,如果不为null,把所有元素根据hash值放入扩容后的nexttable中,在原table的槽内放置一个ForwardingNode 。
1)ForwardingNode是一种临时结点,在扩容进行中才会出现,hash值固定为-1,且不存储实际数据。
2)如果旧table数组的一个hash桶中全部的结点都迁移到了新table中,则在这个桶中放置一个ForwardingNode。
读操作碰到ForwardingNode,将操作转发到扩容后的新table;
写操作碰见,帮助扩容,多线程一起扩容。
ReservationNode
在并发场景下、在从 Key不存在 到 插入 时间间隔内,防止哈希槽被其他线程抢占,当前线程会使用一个reservationNode节点放到槽中并加锁,从而保证线程安全。
1)保留结点.
1)hash值固定为-3, 不保存实际数据
1)只在computeIfAbsent和compute这两个函数式API中充当占位符加锁使用
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Blazor Hybrid适配到HarmonyOS系统
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· 解决跨域问题的这6种方案,真香!
· 分享4款.NET开源、免费、实用的商城系统
· 一套基于 Material Design 规范实现的 Blazor 和 Razor 通用组件库