HashMap原理笔记(JDK1.7)

HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry。这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干。

HashMap数组每一个元素的初始值都是Null。

HashMap通过put方法把元素插入到HashMap,

HashMap的默认初始化长度为16(可显式指定),HashMap的默认负载因子为0.75(可显式指定),插入时,当计算出HashMap中的数量达到了16*0.75(12)时,对HashMap的容量进行扩容,扩容为原来的两倍,扩容时建立更大的数组,然后移动数据到相应位置。扩容这个过程涉及到 rehash、复制数据等操作,所以非常消耗性能。

插入时,通过一个哈希函数来确定Entry在数组中的插入位置(index),

比如调用 hashMap.put("apple", 0) ,插入一个Key为“apple"的元素:

index = Hash(“apple”) HashMap采用位运算的哈希函数计算index

假定最后计算出的index是2,那么结果如下:

因为HahMap的数组长度是有限的,当插入的Entry越来越多的时候,再完美的哈希函数也会出现哈希冲突的情况,

比如在插入第六个Entry时计算出的index还是2:

HashMap中使用链表解决冲突:

HashMap数组的每一个元素不止是一个Entry对象,也是一个链表的头节点。每一个Entry对象通过Next指针指向它的下一个Entry节点。当新来的Entry映射到冲突的数组位置时,只需要插入到对应的链表即可:

所以说HashMap的数据结构是通过数组加链表实现的。数组和链表的存取速度较快,可以加快查询。

 

HashMap通过get方法通过key来查找value,

首先会把输入的Key做一次Hash映射,得到对应的index:

index = Hash(“apple”)

由于刚才所说的Hash冲突,查找的index位置有可能匹配到多个Entry,这时候就需要顺着对应链表的头节点,一个一个向下来查找。假设我们要查找的Key是“apple”:

查找时,会先判断该index位置的值是否为链表,不是链表就根据key和key的hashCode来返回值,

为链表则需要遍历直到 key 及 hashcode 相等时候就返回值。

啥都没取到就直接返回 null 。

所以实际查找时,找到index等于2的数组位置的值,因为它是一个链表,对它进行遍历,找到key为apple

的值返回。

 

在高并发的场景下,两个线程一起对HashMap扩容,会使链表上的引用关系变成:

节点a和b互相引用,形成了一个环,当在数组该位置get寻找对应的key时,就发生了死循环。而且还伴随有数据丢失的问题。

所以在并发的情况,发生扩容时,可能会产生循环链表,在执行get的时候,会触发死循环,引起CPU的100%问题,所以一定要避免在并发环境下使用HashMap。要并发就使用ConcurrentHashmap。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值