前言
最近迷上了并发编程。并发这玩意怎么说呢,就是你平时工作用不到,一用就用在面试上。这不,又卷起了并发容器。
那说起并发容器,你一定也知道那几个,CopyOnWriteArrayList、并发队列BlockingQueue,等等。但是作为面试的典中典,聊到并发容器就无法绕开ConcurrentHashMap。
由于篇幅原因,这篇文章不会具体解释那些较为基础的问题,比如为什么散列表数组的长度一定要是2的n次方等。将更多围绕并发这个话题。如有需要,之后会另外讲解。
所以本文我们就来深入聊聊这个大厂面试青睐的对象,八股文里的兰博基尼:ConcurrentHashMap。
以下的技术点都基于JDK1.8~
基础回顾
我们都知道,从JDK1.8起,ConcurrentHashMap底层的数据结构就已经从原来的Segment分段锁变为了数组 + 链表 + 红黑树的形态。
它是一款并发容器,一款装数据的容器在并发环境下铁定就会有各种各样的问题。你在单线程环境下玩单机,并发环境下就会有别的线程和你抢数据,抢桶位。因此编写JUC包的大神Doug Lea也都为这些场景一一做了适配,可以说是绝对的并发安全,至少运行了这么多年了也没遇到什么bug。
红黑树
红黑树数据结构
JDK1.8这里的红黑树,准确的来说是一个TreeBin代理类,它作为红黑树的具体实现起存储作用,而TreeNode是封装红黑树的数据结构,所以你可以理解TreeBin就是封装TreeNode的一个容器。
红黑树在ConcurrentHashMap里面的体现是一个双向链表:
红黑树插入数据
在这里,红黑树维护一个字段dir。
在插入数据的时候会获取节点的hash值,从而与当前节点p的hash值比较,若插入节点的hash小于当前节点,则dir的值为-1,否则为1: