今天博主主要分享这些默认值的原因,也就是它为什么是这个值。
初始容量
Capacity:16
初始容量为16,为什么?
- 首先,选取为 2 n 2^n 2n原因是因为取模时直接hash&(length-1)进行运算,提高运算的速度,这也是为什么扩容时是 2 n 2^n 2n的原因。
- 其次,为什么是16呢?作为初始容量,太大了,浪费空间,太小了,放两个元素就需要扩容,所以16作为一个相对中间的经验值,就被选定了。
链表转化红黑树长度阈值
treeifyThreshlid:8
阈值为8,为什么?
Ideally, under random hashCodes, the frequency of nodes in bins follows a 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(-0.5) 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
- 理想状态下,Loadfactor为0.75时,桶中节点分布频率遵循入参为0.5的泊松分布。进而推出桶中链表长度的概率,当链表长度为8时,概率为0.00000006,这是非常低的。所以选用了8来作为阈值。当比7低时,链表的平均查找速度是可接受的,当链表转为红黑树时,空间会扩大两倍,但因为出现这个的概率是非常低的,那么如果出现这种情况,转为红黑树的空间是可接受的。
- 当阈值为8时,链表的平均查找为8/2=4,红黑树的平均查找为log8=3,查找速度更短,而且随着节点的增多,差距更明显。
负载因子
loadFactor:0.75
负载因子为0.75,为什么?
- 当负载因在过大时,桶中发生碰撞的概率就越大,负载因子过小,那么存放几个元素就要扩容。0.75是一个折中的选择。
- 在理想状态下(hash分布均匀的条件)下,loadfactor=0.75的情况下,桶中节点的分布概率遵循泊松分布。而根据这个,也可得出为什么红黑树阈值为8。
红黑树转化容量阈值
min_treeify_capacity = 64
原因:是为了防止初始时拆入过多同一位置的元素导致没必要的转化。
为什么是64?
都是容量和时间的一个平衡,因为treeNode比node空间大一倍,
红黑树转链表阈值
untreeifyThreshold = 6
原因:
log6 = 2.6,6/2=3,查找接近,但是树更浪费空间,所以转换为链表。
数据分析
当数据是万级数据时,初始容量为16存入速度更快,8和32速度更慢
当数据在万级以上时,初始容量8更快,16,32较慢(创建表占主要时间)
当数据在万级以下时,32更快(扩容在主要消耗时间)
当数据在百万级以上时,初始容量在标准容量(数据量/3*4+1),速度较慢,体现不到优势,说明此时创建table占主要时间消耗
当数据在百万级一下时,标准容量时间更短。