JDK1.7及其之前的HashMap死循环问题

只是在jdk1.7以及多线程下进行哈希扩容的情况下才会发生

本质是产生了一个循环链表,导致在get或put新元素的时候一直循环遍历链表

主要发生在hashmap的transfer方法中

    //转移原哈希表中的元素到新的哈希表中
    void transfer(Entry[] newTable, boolean rehash) {
        //获取新数组容量
        int newCapacity = newTable.length;
        //遍历老哈希表Entry[]数组
        for (Entry<K,V> e : table) {
            //当这个Entry不为空
            while(null != e) {
                //将e的下一个节点赋值给next
                Entry<K,V> next = e.next;
                //一般不需要重新计算哈希值
                if (rehash) {
                    e.hash = null == e.key ? 0 : hash(e.key);
                }
                //重新计算需要在新数组插入的数组下标
                int i = indexFor(e.hash, newCapacity);
                //将e元素插入到newTable[i]的头上,即将e的next属性指向newTable[i]
                e.next = newTable[i];
                //将e元素插入到newTable[i]上(头插法)
                newTable[i] = e;
                //开始转移下一个元素
                e = next;
            }
        }
    }

如果有两个线程对同一个hashmap同时开始扩容,进入到transfer方法

那么在各自线程中会分别生成一个新的Entry[] newTable

两个线程中的 e 和 next 都是局部变量,但是它们都指向了在堆内存当中的同一个对象

如图所示:

 

如果在第二个线程走到if(rehash)方法时发生了阻塞。

第一个线程正常执行,并无异常,执行结果:

 

然后线程2结束阻塞开始执行

此时的e2仍然指向堆内存当中的3号元素,next2也仍然指向堆内存中的2号元素,但是3号元素的next属性不再指向2号元素,而是指向了null.此时开始继续循环:

while(null != e) {

                Entry<K,V> next = e.next;               
                if (rehash) {
                    e.hash = null == e.key ? 0 : hash(e.key);
                }
                //从这里继续循环               
                int i = indexFor(e.hash, newCapacity);             
                e.next = newTable[i];               
                newTable[i] = e;                
                e = next;
            }

第一次循环:将e2所指向的3号元素插入到新数组中,然后e2指向2号元素(因为此时next2指向2号元素),第一次循环结束

第二次循环:将e2指向的2号元素插入到新数组中(采用头插法),而此时的2号元素的next是指向3号元素的,所以在第二次循环结束之后,e2又指向了3号元素

第三次循环:将3号元素的next属性指向newTable[i],也就是当前在newTable[i]上的2号节点,然后将3号元素放到链表的头节点也就是newTable[i],此时就造成了循环链表的局面。

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值