HashMap1.7 头插法造成死循环的原因

一:概述

HashMap1.7当中,扩容的时候,采用的是头插法转移结点,在多线程并发的情况下会造成链表死循环的问题。

二:图解

假设有两个线程,线程1和线程2,两个线程进行hashMap的put操作,触发了扩容。

下面是扩容的时候结点转移的关键代码

void transfer(Entry[] newTable) {
      Entry[] src = table; 
      int newCapacity = newTable.length;
      for (int j = 0; j < src.length; j++) { 
          Entry<K,V> e = src[j];           
          if (e != null) {//两个线程都先进入if
              src[j] = null; 
              do { 
                  Entry<K,V> next = e.next; 
                 int i = indexFor(e.hash, newCapacity);
                 e.next = newTable[i]; //线程1 这里还没执行 停下
                 newTable[i] = e;  
                 e = next;             
             } while (e != null);
         }
     }
 }

线程1和线程2 都进入if,然后线程1没有拿到cpu的资源在上面代码注释的地方停下了。此时的变量指针如下图所示:

在这里插入图片描述

记住 线程1中 E变量指向a结点,next变量指向b结点。

下面是线程2 拿到cpu的资源,执行结点转移

在这里插入图片描述

在这里插入图片描述

 

在这里插入图片描述

在这里插入图片描述

线程2停下,轮到线程1

因为之前线程1中E变量指向的是a结点,next变量指向的是b结点,所以如下图所示:

在这里插入图片描述

再来看看 刚才线程是在e.next = newTable[i] 这句代码还没执行的时候停下的,那么现在就要执行这一句代码

void transfer(Entry[] newTable) {
      Entry[] src = table; 
      int newCapacity = newTable.length;
      for (int j = 0; j < src.length; j++) { 
          Entry<K,V> e = src[j];           
          if (e != null) {//两个线程都先进入if
              src[j] = null; 
              do { 
                  Entry<K,V> next = e.next; 
                 int i = indexFor(e.hash, newCapacity);
                 e.next = newTable[i]; //线程1刚才在这里停下,所以现在从这一句代码开始执行
                 newTable[i] = e;  
                 e = next;             
             } while (e != null);
         }
     }
 }

此时线程1 执行代码之后,就造成了链表的死循环,结果如下:

在这里插入图片描述

参考博客

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值