存储结构?
- JDK1.8 之前 数组+链表
- JDK1.8几之后 数组+链表+红黑树
hashmap的长度为什么是2的N次幂?
- 向hashMap中添加元素的时候,需要计算下标的值,hash%lengh = hash & (length - 1)的前提是length是2的N次幂,位运算比取模效率高,所以hashmap使用的是位运算
- 均匀分布
为什么链表节点大于8才转换为红黑树?
- 在hash算法满足柏松分布概率情况下,,hash碰撞超过8的概率很小
加载因子0.75 也就是默认12
- 加载因子越小那么数据约稀疏,出现链表的概率也就越小,反之越大
- 设置为0.75只是一个参考值
put方法的过程?
- 计算桶的索引位置 hash & (length - 1)
- 如果桶上没有碰撞直接插入
- 如果有碰撞
-
- 如果当前桶是红黑树则使用红黑树的插入方法
-
- 如果当前是链表则使用链表插入方法,链表长度大于8 将其转换为红黑树
- 如果桶中存在重复的key,则更新值
- 如果size大于阈值则进行扩容
get方法过程?
- 计算桶的索引位置 hash & (length - 1)
- 桶上的key就是查询的结果
- 桶上后续为链表,查询链表
- 桶上后续为红黑树,查找红黑树
扩容?
- 当hashmap的元素个数超过 capacity*loadfactory 则进行扩容为2N
- 当hashmap的size没有达到64的时候,链表长度达到8个,hashmap会先扩容解决,反之链表转换为红黑树
- 扩容时数据要么在原位置,要么在原位置 + 旧容量这个位置
为什么使用红黑树而不是用二叉树?
- 二叉树极限情况下与链表没区别,红黑树牺牲插入的性能提高查询的性能
JDK1.8及之后为什么头插法更换为尾插法?
- 尾插法是指在解决hash冲突时,将新的键值对插入到链表或者红黑树的末尾,而不是插入到链表或者红黑树的头部。
- 多个闲层resize的场景下,尾插法能够防止出现死循环,在resize的时候尾插法的话不会改变原本链表元素的顺序,头插法改变了原本链表元素的指针
两个线程T1、T2准备同时进行扩容
T1完成扩容
当线程T1执行完成之后,线程T2恢复执行时,死循环就发生了