hashMap 1.7 视频笔记

hashMap 1.7

put 方法的调用

首先判断数组是否进行了初始化,如果没有的话,调用方法进行初始话,把传入的参数进行2的次方数的转换,先转换为小于等于最最接近它的2的次方数,然后减一,在进行右移一位,然后再找大于等于的2的次方数。初始化完成后,判断key是否为null,如果为null,调用方法把值存在table【0】处,不为null,调用hashcode方法进行key的hash值的计算,不是简单的hash计算,要进行扰动,把hash值二进制数值进行位运算,左移,右移,让hash指的高位参与到运算中来,然后返回一个具体的hash值,计算entry在数组中的存储位置,通过hash值和数组长度进行按位与(h&(length-1))和取余的想法一样,只不过计算效率更高,都为一则为一,否则是0,例如:key是21,计算得到的hash值的二进制数是 0001 0101 数组长度为16,减一后的二进制数为0000 1111,按位与得到的结果就是 0000 0101,就算它高位有值,(length-1)的二进制数高位没有值,按位与后还是0,这样就保证了最后的结果是0000-1111之间,也就是0-15之间,前方的hash扰动是防止高位不同,低位相同,然后返回的存储位置集中,导致链表过长,通过扰动,使hash值更加分散,也使的链表存储更加均匀,计算出存储位置后,判断当前位置是否为null,为null的话,直接新建一个entry,判断是否需要扩容,不需要的话,直接把entry存到的table【i】处,,不为null的话,遍历当前位置的链表,判断key是否存在,如果存在的话,则进行value值的覆盖,并且把原来的值返回。不存在的话,直接新建一个entry,判断是否需要扩容,不需要的话,采用头插法,插到数组的table【i】处。

resize 扩容原理

创建新数组—>进行数据的转移—>再把完成转移后的数组赋值给变量table

在插入entry节点前进行判断,判断条件是当前的hashMap存的总的元素个数与数组长度的0.75倍(默认)进行比较,并且计算出来的当前存的位置不为空,会建一个长度是原来数组二倍的新数组,扩容完成后,要进行数据的迁移,也就是把旧数组中的数据移动到新的数组中,会先遍历旧数组得到每一个table【i】,然后在遍历每一个table【i】上的所有元素,获取到每一个entry节点,获取他的hash值,然后进行判断,为true话,会进行hash值的重新计算,再用新的hash值和数组长度计算出entry在新数组中的存储位置,实际上不配置的话值默认为是false,会直接根据原来的hash值和新的数组长度计算出entry在新数组中的存储位置,这个有规律可循,比如,在旧数组中我们存储的hash值的二进制数为0111 1010,参与到旧数组(默认长度16)中的hash&(length-1)计算后,得到的低四位是1010,也就是数组的table【10】的位置,新数组中,hash值没有改变,用新的长度进行计算在新数组中存储的位置,hash值依然是0111 1010,数组的长度是32,对应的(length-1)之后的hash值为0001 1111,得到的结果是0001 1010,和原来相比的话存储位置加了16,也就是存在新数组的table【26】的位置,再如原hash值的是01101010的话,在旧的数组中也是存在table【10】,但是在新数组中的计算结果依然是1010,也就是说,存储位置没有发生改变,实际上,在不发生hash重新计算的话,元素在新数组中的存储位置,要么是和旧数组中相同的位置,要么就是在原数组存储位置的基础上加原数组的长度的位置,这就是数据迁移存储位置的确定。正常情况下,采用头插法,entry在转移完成后,会由原来数组上的1->2->3 ,变成新数组上的3->2->1,顺序发生反转。

hashmap不安全的原因

假如有a,b两个线程同时操作hashmap,同时走进扩容方法,他们分别new了一个新的数组,当走到transfer方法中对链表进行遍历的下一行时,a线程挂起,b线程正常执行,当b线程完成数据的迁移后,此时a线程醒了过来,这时候因为b的迁移,导致entry的顺序反了过来,由原来的123变成了321,但是在a线程挂起前,他已经把指针的位置指向给确定了,然后开始进行entry的遍历,一个entry节点正常存储,第二个也正常存储,当进行第三次循环的时候,第二个的指针又会指会第一个的位置,这样就产生了一个循环链表,导致死锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值