HashMap其他问题
HashMap中单链表与红黑树转换的规则
在JDK8之前,桶结构是链表,JDK8中,桶结构会根据桶中元素个数在链表与红黑树两种数据结构中转换。桶中数量超过8个,就由链表转换为红黑树,桶中数量减少到6,就转换为链表。为什么是8和6呢?红黑树的平均查找时间复杂度为O(log(n)),链表平均查找时间复杂度O(n/2)
桶中元素个数 | 链表平均查找时间复杂度O(n/2) | 红黑树平均查找时间复杂度O(log(n)) |
1 | 0.5 | 0 |
2 | 1 | 1 |
3 | 1.5 | 1.58 |
4 | 2 | 2 |
5 | 2.5 | 2.32 |
6 | 3 | 2.58 |
7 | 3.5 | 2.81 |
8 | 4 | 3 |
9 | 4.5 | 3.17 |
10 | 5 | 3.32 |
12 | 6 | 3.58 |
16 | 8 | 4 |
32 | 16 | 5 |
在元素个数≤6的时候,两种数据结构的平均查找复杂度差别不大,而在≥8的时候,红黑树相比于链表的平均时间复杂度显示出明显的优势。链表结构较为简单,而红黑树的实现则很复杂,这种设计是在复杂度和效率上寻求一种平衡。
HashMap的负载因子为什么是0.75
默认负载因子(0.75)在时间和空间成本上提供了很好的折衷:负载因子较大时,table数组扩容的可能性就会少,所以相对占用内存较少(空间上较少),但是每条entry链上的元素会相对较多,查询的时间也会增长(时间上较多)。反之当负载因子较少的时候,给table数组扩容的可能性就高,那么内存空间占用就多,但是entry链上的元素就会相对较少,查出的时间也会减少。
在理想情况下,使用随机哈希码,不同键值对table数组中各个元素中出现的频率遵循泊松分布。TODO:理解注释中的这段话。
HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么?
①put后可能导致get死循环,具体表现为CPU使用率100%:
②put的时候可能导致元素丢失:执行addEntry(hash, key, value, i),如果有产生哈希碰撞,导致两个线程得到同样的bucketIndex去存储,就可能会出现覆盖丢失的情况:
内容参考
Last updated