负载因子 ( loadFactor)
负载因子是扩充 table 的指标量, 默认 0.75, 当 Map中键值对数量 / bins总量 > loadFactor 时, 扩容 table 到原来容量的两倍.
负载因子的意义: 负载因子是在碰撞概率和空间利用率之间进行权衡的调节器. 从直观上感觉, 负载因子描述了 table 的稀疏程度.
- 负载因子越小, 出现 hash 碰撞的概率越低, bin 中的链表越短; 同时空间利用率低 (空 bin 多, 浪费). Table 看上去非常稀疏.
- 负载因子越大, 出现 hash 碰撞的概率越高, bin 中的链表越长; 同时空间利率也高 (空 bin 少, 不浪费). Table 看上去非常稠密.
看图从直观上感觉 table 的稀疏程度:

左侧 table 加载因子 = 0.1, 右侧 table 加载因子 = 0.6. 不过实际上 bins 的分布不会这么均匀.
例如:
-
场景一: table 长度 = 10, 负载因子 = 0.1, 每加入一个元素就会扩容, 浪费了空间, 但一定不会出现碰撞.
-
场景二: 如果将场景一中的负载因子修改为1, 则加入 10 个元素后才会触发扩容, 可想而知因为这 10 个元素是通过 hash % size 落入 table 中的, 最理想的状态是每个 bulk 中落入一个元素, 但几乎可以肯定的是, 有的 bulk 中落入了两个或更多元素 (形成链表), 即出现了碰撞.
默认值为什么是 0.75?
0.75 是权衡的结果, 当加载因子为 0.75 时, bin 中增加节点的概率符合泊松分布(λ=0.5), 从分布中可以看出来:
bin 中链表长度 = 8 时, 新节点加入的概率非常小, 而长度 8 也是从链表转变成红黑树的边界, 所以, 当加载因子为 0.75 的时候, 几乎不存在转换成红黑树的情况. 大于 0.75 则冲突概率增加, 转换成红黑树的几率增加. 小于 0.75 则浪费更多空间.
0: 0.60653066 // 加载因子=0.75时, bin中链表长度=0, 随机节点落入 bin 中的概率 1: 0.30326533 // 加载因子=0.75时, bin中链表长度=1, 随机节点落入 bin 中的概率 2: 0.07581633 // ... 3: 0.01263606 4: 0.00157952 5: 0.00015795 6: 0.00001316 7: 0.00000094 8: 0.00000006 // 加载因子=0.75时, bin中链表长度=8, 随机节点落入 bin 中的概率
负载因子可以在实例化 HashMap 时指定, 其值可以是任意大于 0 的浮点数, 但不能小于零(小于 0 抛出异常 java.lang.IllegalArgumentException).
扩容实现
HashMap 内部的变量
threshold保存了下一次需要扩容时的 entry 数量门限值, 计算公式: threshold = 当前容量 * 负载因子. 使用threshold可以避免重复的计算.
性能选择
迭代性能
Iterate 性能与 table 的稀疏程度有关, table 比较稠密 (即比较少的空 bin), 则迭代性能更好, 优化方法:
- 初始化表容量宜小不宜大. 因为迭代的对象是 table , table 的 size 小一些, 空 bin 出现的可能性就小一些, table 更稠密, 迭代性能更好.
- 负载因子宜大不宜小. 负载因子越大, table 中的 bins 的使用率越高, 整个 table 更稠密.
查找性能
查找性能与 bins 的 hash 冲突情况有关, 冲突少, 查找效率高. 优化方法:
- 初始化表容量宜大不宜小, 容量大, hash 冲突少, 查找效率高.
- 负载因子宜小不宜大, 负载因子越小, 碰撞的几率越小.
appendix
- Table: It is a array of `Object of either Node or TreeNode.
- Bin: A bin refer to a bucket that is a element in array of table in hashmap.
vs HashTable
| HashMap | HashTable |
|---|---|
| 线程不安全 | 线程安全 |
| 允许 null key 和 null value | 不允许 null key 或者 null value |
| Java 1.2 加入 | Java 最早加入 |
| faster | 更慢, 不建议使用 |

负载因子是HashMap扩容的指标,当键值对数量超过bins总量的0.75时,HashMap会扩容到原来的两倍。负载因子越小,碰撞概率降低但空间利用率下降;越大则碰撞概率增加。默认0.75是考虑到冲突概率和转换为红黑树的平衡。初始化容量和负载因子的选择影响HashMap的迭代和查找性能。
1840

被折叠的 条评论
为什么被折叠?



