• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

张秋天

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

《集合》之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中充当占位符加锁使用

 

posted on 2020-12-19 22:59  张秋天  阅读(246)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3