请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

关于ConcurrentHashMap写的同时读

图片描述

悟空老师,您说的是对的,ConcurrentHashMap之前我没有看源码,想当然的认为和HashMap一样会将红黑树的头节点移动到链表的第一个位置,从而改变链表的结构。
如下是HashMap的源码

图片描述

moveRootToFront会将平衡后红黑树的头节点移动到链表的第一个位置。其他Node在链表的位置不变。

而ConcurrentHashMap并没有这么做,而是用一个TreeBin的数据结构记录了红黑树的头节点,如下
图片描述

当链表中添加了一个Node从而满足条件转换为红黑树后,会调用treeifyBin()方法
图片描述

treeyIfyBin方法还是会和HashMap一样维护一个双向链表,这个双向链表的顺序和单向链表的顺序是一模一样的
图片描述

并且会将双向链表头节点构建为TreeBin类型的,通过TreeBin中维护的root属性构建红黑树或者通过红黑树查找相应的节点。

回到正题,为什么ConcurrentHashMap的读没有锁,在写时候的读也不会出错呢?

  1. 首先Node中的value属性和next属性都被volatile修饰,volatile保证可见性,所以当线程A通过链表读取一个节点时,这时线程B在链表末尾添加了这个节点,因为volatile保证了可见性,所以线程A能立马感知到新添加的这个节点。

  2. 当线程A通过链表读取一个节点时,线程B添加这个节点到链表末尾,即使线程B添加这个节点达到转换为红黑树的条件,但是线程B也是首先将这个节点添加到单向链表之后,才将单向链表转换为双向链表,进而转为红黑树。 此时单向链表的结构并没有改变,所以线程A因为volatile的原因也能感知到新添加的这个节点,当线程A再次调用读取方法时,才会通过红黑树的方式查找。

所以ConcurrentHashMap的get并不需要添加任何锁,也能保证写同时读的安全性。

正在回答 回答被采纳积分+3

1回答

悟空 2021-03-06 15:36:03

给你点大大的赞!

0 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信