2024-03-23  阅读(99)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1471739948

ConcurrentHashMap 的底层结果如下:

学过 ConcurrentHashMap 小伙伴都知道,ConcurrentHashMap 开始时是链表结构,当链表长度为 8 时,就开始由链表转换为红黑树。

这里我们要回答两个问题:

  • 1、为什么要转为红黑树

主要原因还是性能。

我们知道链表的查询元素时间复杂度为 O(n),这就意味着随着链表长度的增加,查找效率会逐步降低。而红黑树是一种平衡二叉树,时间复杂度为 O(log n),查询效率明显高于链表。

  • 2、为什么是 8 的时候转换为红黑树

ConcurrentHashMap 中,要满足两个条件才会由链表转换为红黑树:

  • ConcurrentHashMap 总结点数大于 64

这是为了避免在哈希表较小的情况下就进行转换,当哈希表较小的时候,链表的查询效率通常是可以接受的。同时红黑树中的 TreeNode 是链表中的 Node 所占空间的 2 倍,如果过早地转换会浪费空间。同时,红黑树的数据结构相比链表要复杂得多,维护成本较高。

  • ConcurrentHashMap 一个桶(bucket)中的节点数量大于 8

当链表长度达到 8 时,链表会转换为红黑树,而当其降为 6 时,红黑树又会转换回去。这体现的是时间和空间平衡的思想。

刚刚开始使用链表是因为链表占用空间小,数据量少,所以查询效率也没太大问题。但是当链表越来越长时,就需要用红黑树的形式来保证查询的效率。那什么时候转换为红黑树呢?这个阈值的确认是基于经验和实验。

源码中有这样一段描述:

Because TreeNodes are about twice the size of regular nodes, we use them only when bins contain enough nodes to warrant use (see TREEIFY_THRESHOLD). And when they become too small (due to removal or resizing) they are converted back to plain bins. In usages with well-distributed user hashCodes, tree bins are rarely used. Ideally, under random hashCodes, the frequency of nodes in bins follows a Poisson distribution (http://en.wikipedia.org/wiki/Poisson_distribution) with a parameter of about 0.5 on average for the default resizing threshold of 0.75, although with a large variance because of resizing granularity. Ignoring variance, the expected occurrences of list size k are (exp(-pow(0.5, k) / factorial(k)). The first values are:
 
0: 0.60653066
1: 0.30326533
2: 0.07581633
3: 0.01263606
4: 0.00157952
5: 0.00015795
6: 0.00001316
7: 0.00000094
8: 0.00000006
more: less than 1 in ten million

这段话的大致意思是:当 hashCode 离散性很好的时候,红黑树使用的概率会非常小,因为各个值都均匀分布,很少会出现链表很长的情况,在理想情况下,桶中节点数概率(链表长度)符合泊松分布(如上),只有0.00000006 的概率才会出现桶中节点数节点为 8 的情况。所以,在理想情况下,我们一般都不会用到红黑树。

但是,每个人的算法水平参差不齐,无法保证实现的 Hash 算法就是理想的,如果出现数据分布不均匀的情况,就可以利用红黑树来提升查询性能。

所以,链表长度超过 8 就转换为红黑树的设计,更多的一种防御措施,防止用户实现了不好的 Hash 算法,导致链表过长而使查询效率低下。所以,在平时开发过程中,如果遇到 HashMap 或是 ConcurrentHashMap内部出现了红黑树的结构,有可能是你 hash 算法不够优秀,需要进行优化!

阅读全文
  • 点赞