文章目录

  • 前置知识
  • 死循环执行步骤1
  • 死循环执行步骤2
  • 死循环执行步骤3
  • 解决方案
  • 总结

前置知识

HashMap死循环是一个比较常见、比较经典的问题,在日常的面试中出现的频率比较高,所以接下来咱们通过图解的方式,带大家彻底理解死循环的原因。

死循环问题发生在 JDK1.7 版本中,造成这个问题主要是由于HashMap自身的运行机制,加上并发操作,从而导致了死循环。 在 JDK1.7 中HashMap的底层数据实现是数组+链表的方式,如下图所示:


HashMap在数据添加时使用的是头插入,如下图所示:


HashMap正常情况下的扩容实现如下图所示:


HashMap的节点会依次转移到新HashMap中,旧HashMap转移的顺序是 A、B、C,而新HashMap使用的是头插法,所以最终在新HashMap中的顺序是 C、B、A,也就是上图展示的那样。有了这些前置知识之后,咱们来看死循环是如何诞生的?

死循环执行步骤1

死循环是因为并发HashMap扩容导致的,并发扩容的第一步,线程T1和线程T2要对HashMap进行扩容操作,此时T1T2指向的是链表的头结点元素A,而T1T2的下一个节点,也就是T1.nextT2.next指向的是B节点,如下图所示:

死循环执行步骤2

死循环的第二步操作是,线程T2时间片用完进入休眠状态,而线程T1开始执行扩容操作,一直到线程T1扩容完成后,线程T2才被唤醒,扩容之后的场景如下图所示:


从上图可知线程T1执行之后,因为是头插法,所以HashMap的顺序已经发生了改变,但线程T2对于发生的一切是不可知的,所以它的指向元素依然没变,如上图展示的那样,T2指向的是A元素,T2.next指向的节点是B元素。

死循环执行步骤3

当线程T1执行完,而线程T2恢复执行时,死循环就建立了,如下图所示:

因为T1执行完扩容之后B节点的下一个节点是A,而T2线程指向的首节点是A,第二个节点是B,这个顺序刚好和T1扩完容完之后的节点顺序是相反的。T1执行完之后的顺序是BA,而T2的顺序是AB,这样A节点和B节点就形成死循环了,这就是HashMap死循环导致的原因。

解决方案

HashMap死循环的常用解决方案有以下3个:

  • 使用线程安全容器ConcurrentHashMap替代(推荐使用此方案)。
  • 使用线程安全容器Hashtable替代(性能低,不建议使用)。
  • 使用synchronizedLock加锁HashMap之后,再进行操作,相当于多线程排队执行(比较麻烦,也不建议使用)。

总结

HashMap死循环发生在 JDK1.7 版本中,形成死循环的原因是HashMap在 JDK1.7 使用的是头插法,头插法+链表+多线程并发+HashMap扩容,这几个点加在一起就形成了HashMap的死循环,解决死锁可以采用线程安全容器ConcurrentHashMap替代。 ​


  • 原文链接:https://www.zhihu.com/question/394039290

详述 JDK1.7 中 HashMap 会发生死链的原因相关推荐

  1. [Java]JDK1.7中HashMap的并发死链

    [Java]JDK1.7中HashMap的并发死链 HashMap的并发死链现象发生在扩容时,在扩容过程中**transfer()**方法负责把旧的键值对转移到新的表中,其代码如下: void tra ...

  2. Java中的集合类——HashMap中的并发死链

    Java中的集合类--HashMap中的并发死链 ReHash过程 正常的ReHash过程: 并发的Rehash过程 解决办法 ReHash过程 正常的ReHash过程: 并发的Rehash过程 (1 ...

  3. JDK1.7和JDK1.8中HashMap是线程不安全的,并发容器ConcurrentHashMap模型

    一.HashMap是线程不安全的 前言 只要是对于集合有一定了解的一定都知道HashMap是线程不安全的,我们应该使用ConcurrentHashMap.但是为什么HashMap是线程不安全的呢,之前 ...

  4. Day1、为什么JDK1.8中HashMap从头插入改成尾插入

    目录 Day1.为什么JDK1.8中HashMap从头插入改成尾插入 存储方式 静态常量 插入元素 扩容 拓展问题 1.为什么JDK1.8采用红黑树存储Hash冲突的元素? 2.为什么在长度小于8时使 ...

  5. JDK1.7中HashMap底层实现原理

    JDK1.7中HashMap底层实现原理 一.数据结构 HashMap中的数据结构是数组+单链表的组合,以键值对(key-value)的形式存储元素的,通过put()和get()方法储存和获取对象. ...

  6. jdk1.8中HashMap扰动函数及数组长度为什么是2的n次方介绍

    文章目录 前言 一.什么是二进制? 二.计算机采用二进制的原因 三.十进制与二进制相互转换 十进制转成二进制 二进制转换为十进制 与.或.异或运算 按位异或 按位与运算 按位或运算 Jdk1.8中Ha ...

  7. 七、JDK1.7中HashMap扩容机制

    导读 前面文章一.深入理解-Java集合初篇 中我们对Java的集合体系进行一个简单的分析介绍,上两篇文章二.Jdk1.7和1.8中HashMap数据结构及源码分析 .三.JDK1.7和1.8Hash ...

  8. 八、JDK1.8中HashMap扩容机制

    导读 前面文章一.深入理解-Java集合初篇 中我们对Java的集合体系进行一个简单的分析介绍,上两篇文章二.Jdk1.7和1.8中HashMap数据结构及源码分析 .三.JDK1.7和1.8Hash ...

  9. 出现无效字符_网站出现死链的原因分析 - 最蜘蛛池租用

    原出处:最蜘蛛池 原文链接:网站出现死链的原因分析 - 最蜘蛛池 死链接是无效链接,外链是seo日常工作的重要组成部分.死链是网站建设中的一个专业术语.它是指那些不能输入的网页链接.在日常的网站操作中 ...

最新文章

  1. Exchange server 2013(十二)IRM故障排除
  2. 附件中可能包含对计算机有害的病毒.附件可能无法正确显示,广西成人高校计算机实用基础统考理论试题(A卷)...
  3. linux终端python自动提示
  4. linux rm 命令删除文件恢复_【Linux】恢复误删除的文件或目录
  5. 下载文件HTTP请求及处理过程
  6. 蜀门Online 简单打怪脚本(vbs)
  7. 计算机应届生面试,计算机应届生面试技巧
  8. LAMP部署phpadmin
  9. 【前端学习项目】web前端#001网页点名器(html+css+js实现用户交互)
  10. 一个屌丝程序员的青春(三三)
  11. 助力企业数字化转型 | 斑羚在线、环宇数通、乘云科技入选阿里云原生合作伙伴计划
  12. webpack 打包报错:Can't resolve '.\dist\bundle.js' in 'E:\vivian....'
  13. php怎么改字体大小,phpstorm修改字体和大小
  14. 二十四进制 加法计数器 并用数码管显示
  15. php excel下载打不开了,php下载excel无法打开的解决方法_PHP教程
  16. 图书管理系统——C语言版
  17. 锁存器、触发器、寄存器
  18. cadence allegro16.6 pcb文件转pads pcb文件方法教程
  19. 图片上添加文字及图片
  20. 日历制作视频教程下载

热门文章

  1. Oracle中decode函数用法解析以及常用场景
  2. 3dsmax怎么添加uv坐标_012:多层贴图UVWMAP(UV坐标)技术
  3. 大数据驱动社会治理的创新转向
  4. Wirecast Pro for Mac 9.0.0 网上直播软件 中文破解版下载
  5. 158万张图像的鉴黄数据集
  6. ArcGIS--GIS常用类型数据下载
  7. 好吧,CSS3 3D transform变换,不过如此!
  8. Android系统学习(37)---Android知识点及资料汇总
  9. 装机(一) ubuntu server 系统安装图文教程
  10. 31.区块链“不可能三角”