带着问题学习
  1. hashmap的底层原理
  2. put原理
  3. hashmap为啥插链表是头插不是尾插
  4. get原理
  5. hashmap初始化大小是多少?为啥要这样设计
  6. 高并发下为啥hashmap会死锁
  7. java8中对hashmap做了哪些优化
1. hashmap的底层原理是 链表+数组+红黑树    链表长度达到8的时候转成红黑树
2. key为 null 直接插入table[0]  ,然后先根据key的 hashcode定位到具体的索引,然后如果hash冲突,就挂链表,头插不是尾插
3. 因为后插入的被查找的概率更大,这样可以减少遍历次数
4.也是先根据key的hashcode找到对应的数组下标,然后如果有多个,遍历链表,如果是treeNode就红黑树查找
5.初始大小是 16,设计为16是为了在hash的时候分布均匀,hashmap没有用取模运算,而是用的位运算&,16-1的的二进制是 1111 这样分布完全取决于key的hashcode,所以扩容的大小一定是2的幂
6.
线程1这会还没有完全开始扩容,但e和next已经指向了,线程2是正常的扩容的,那这会在3这个位置上,就是7->3这个顺序

此时线程一调度回来

https://blog.csdn.net/chenyiminnanjing/article/details/82706942  没看懂的时候静下心来仔细看这篇文章
7. 1.7的数据存储是 数组+链表  1.8变成了数组+链表+红黑树   (链表长度>8 且总容量>64转成红黑树)
    扩容的时候,1.7需要从新hash计算索引位置,1.8通过&运算,不需要重新hash,直接平移就行了  (https://blog.csdn.net/weixin_38937840/article/details/106805496 详细看这篇)
     扩容的时候,1.7是头插,1.8变成了尾差,这样就避免了扩容的时候并发导致的死锁问题