HashMap并发中死循环分析

 

HashMap并发场景分析

背景

看书过程中《Java并发编程的艺术》,在看这本书的过程中,作者提到,在并发编程中,使用HashMap可能导致程序死循环,那么作者说的到底对不对呢,为什么会这样呢,现在有没有进行改进呢,所以就进行查阅资料,进行学习,并总结成以下文章

HashMap并发中存在的问题

  1. 非线程安全

这个是众所周知的

  1. 扩容导致死循环

这个问题 的背景是JDK 1.7中,JDK1.8中hashMap源码进行了修改,应没有此问题,所以导致死循环问题,只在JDK7中存在

并发场景下会导致死循环分析

模拟一个场景,有原HashMap如下: image

多线程场景下,有线程一和线程二,同时对map 进行扩容, image

当线程一执行到如下代码时被挂起 image

此时线程1的数据结构为,table已经扩容完毕,重新计算每个元素位置时被挂起,此时key为3 的还在1的位置, 3的next 为7 image 这时,线程2完成扩容,扩容后的数据结构为 image

当线程1被调度回来执行之后,因为线程一执行的e.next = newTable[i]; 将key3插入到3号位置,同时3.next = key7, 此时e= key3, next = key7;

image

image 当执行到e=next的时候,e=key7,next=key7;

然后开始下一轮while。但此时因为线程二已经将key=7的next设置为key3(问题就在这里,线程二执行的时候,key7.next已经是null了,但这里线程一去执行的时候key7.next却是key3)。所以当第二轮循环开始,执行next=e.next后,next = key3。

image 之后通过头插法,将key7插入key3之前。在执行完next=e.next 之后,e=key3,next=key3;

image

然后开始第三轮循环。e和next都是key3。所以根据头插法。key3又要插入key7之前,这就导致了key3.next为key7,key7.next为key3

image 所以当我们去get值得时候,当定位到3的时候,就会产生死循环。导致永远拿不到数据。

JDK1.8存不存在死循环问题

应该不存在,JDK8中将链表扩容到达一定阈值后,转为红黑树, 没有相关的问题

总结

HashMap之所以在并发下的扩容造成死循环,是因为,多个线程并发进行时,因为一个线程先期完成了扩容,将原Map的链表重新散列到自己的表中,并且链表变成了倒序,后一个线程再扩容时,又进行自己的散列,再次将倒序链表变为正序链表。于是形成了一个环形链表,当get表中不存在的元素时,造成死循环。在1.8当中,链表扩容转为红黑树,没有相关的问题。

参考链接

https://blog.csdn.net/b379685397/article/details/93459564

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值