HashMap多线程下发生死循环的原因

概述


大神陈皓已经在疫苗:JAVA HASHMAP的死循环一文中详细描述了HashMap多线程下产生死循环的原因,我仔细研读了这篇大作,做了一些笔记,加上自己的一些理解
整理出一些信息,发出来与大家交流交流。


HashMap存储的数据结构


陈皓在Hash表数据结构这一节提到了HashMap的数据结构以及扩容问题,关于这一点我之前写过的
HashMap的put和get方法原理HashMap扩容已经有详细的描述了。


多线程rehash的时候如何造成闭环链表


rehash源代码
这里写图片描述

这里写图片描述


正常的rehash过程


数据准备
在size=2的HashMap中按照顺序添加5, 7, 3这三个key,假设按照mod 2的算法来计算元素数组下标,那么key 5,7,3都会落在下标为1的数组桶中(发生hash冲突),如下图:
这里写图片描述

把HashMap的size扩容为4后,rehash的过程

注意,发生hash冲突的5,7,3虽然都是在同一个链表中,但是每个元素都得走rehash的过程,因为HashMap扩容后,这几个元素就未必都是在同一个链表中了

1、第一个是处理3这个key,先把key为3这个元素的next设置为空,并计算它在新数组中的下标,并存到新下标对应桶中,如下图:
这里写图片描述

2、第二个是处理7这个key,按照上面的约定,在新数组中3和7这个两个key还是发生了hash冲突,那么按照HashMap发生冲突的处理代码,链表的第一个元素存储的是最新插入的7,然后next指向3,如下图:
这里写图片描述

3、第三个是处理5这个key,如下图:

这里写图片描述

到这里一次正常rehash过程走完了,最后三个key的存储情况如下图:

这里写图片描述


并发下的rehash过程


当两个并发线程thread1和thread2都同时进入到transfer时,也即是,刚好thread1和thread2都要对HashMap进行扩容,万一这个时候thread1执行下面的代码时,被线程调度器挂起了,而thread2则正常的把扩容的操作做完,如下图:
这里写图片描述
那这个时候,容器的数据存储情况如下:
对于thread1
这里写图片描述

对于thread2

这里写图片描述

这个时候,thread1拥有执行权限了,则继续它的扩容操作,等thread1扩容完后就产生了一个环形链表了(注意这里省略了一些步骤,不太明白的,则可以看我之前写的HashMap的put和get方法原理HashMap扩容)

这里写图片描述

这个时候,如果有个get请求,就有可能发生死循环,一直在链表中绕来绕去的,没法终止。

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值