HashMap是一个存储key-value键值对的集合,每个键值对也叫Entry,每个Entry可以看做是一个链表的节点,每个元素的初始值都是null。
新插入一个key为“dog”的元素,调用hashMap.put("dog",0):
首先利用哈希函数来确定Entry的插入位置,index=Hash(“dog”)放入指定的位置,若该位置无元素,Entry放入该位置,若该位置有元素,及发生hash冲突,执行3。我们的Entry元素的next指针指向该位置存在的Entry对象,可抽象理解为纵向插入链表中。需要注意的是,新来的Entry对象的对象使用的是头插法,因为发明者认为后插入的Entry被查找的可能性更大。查找一个key为“dog”的元素,调用hashMap.get("dog",0):
get方法根据index=Hash("dog"),找到该位置的索引如果该位置有多个元素Entry,那么顺着对应链表的头结点一个一个找,找到为止。初始长度是16,每次自动拓展或者手动扩展失,长度都必须是2的幂,之所以这样选择是因为key映射到index的Hash算法
index = HashCode(Key) & (Length - 1),Hash算法最终得到的index结果,完全取决于Key的Hashcode值的最后几位。2的幂-1的二进制都是111111....,index的结果会更加均衡分布,
HashMap是线程安全的吗?不是线程安全的,在HashMap随着插入元素达到一定的饱和度时,会进行Resize操作,影响Resize的操作有两个:
Capacity:HashMap的当前长度。HashMap的长度是2的幂LoadFactor:HashMap负载因子,默认值为0.75f。衡量HashMap是否进行Resize的条件如下:HashMap.Size >= Capacity * LoadFactor
Resize的两个步骤:
扩容:创建一个新的Entry数组,长度为原来的二倍。ReHash:遍历原Entry数组,把所有的Entry根剧新的Hash算法重新Hash到新数组。HashMap在设计上很完美,不过存在线程安全问题,在Resize达到临界点时,两个线程同时操作可能出现死锁。
高并发情况下,为什么HashMap可能出现死锁?https://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653192000&idx=1&sn=118cee6d1c67e7b8e4f762af3e61643e&chksm=8c990d9abbee848c739aeaf25893ae4382eca90642f65fc9b8eb76d58d6e7adebe65da03f80d&scene=21#wechat_redirect
在Java 8中HashMap的结构有怎么样的优化?