详述 JDK1.7 中 HashMap 会发生死链的原因
文章目录
- 前置知识
- 死循环执行步骤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
进行扩容操作,此时T1
和T2
指向的是链表的头结点元素A
,而T1
和T2
的下一个节点,也就是T1.next
和T2.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
执行完之后的顺序是B
到A
,而T2
的顺序是A
到B
,这样A
节点和B
节点就形成死循环了,这就是HashMap
死循环导致的原因。
解决方案
HashMap
死循环的常用解决方案有以下3个:
- 使用线程安全容器
ConcurrentHashMap
替代(推荐使用此方案)。 - 使用线程安全容器
Hashtable
替代(性能低,不建议使用)。 - 使用
synchronized
或Lock
加锁HashMap
之后,再进行操作,相当于多线程排队执行(比较麻烦,也不建议使用)。
总结
HashMap
死循环发生在 JDK1.7 版本中,形成死循环的原因是HashMap
在 JDK1.7 使用的是头插法,头插法+链表+多线程并发+HashMap
扩容,这几个点加在一起就形成了HashMap
的死循环,解决死锁可以采用线程安全容器ConcurrentHashMap
替代。
- 原文链接:https://www.zhihu.com/question/394039290
详述 JDK1.7 中 HashMap 会发生死链的原因相关推荐
- [Java]JDK1.7中HashMap的并发死链
[Java]JDK1.7中HashMap的并发死链 HashMap的并发死链现象发生在扩容时,在扩容过程中**transfer()**方法负责把旧的键值对转移到新的表中,其代码如下: void tra ...
- Java中的集合类——HashMap中的并发死链
Java中的集合类--HashMap中的并发死链 ReHash过程 正常的ReHash过程: 并发的Rehash过程 解决办法 ReHash过程 正常的ReHash过程: 并发的Rehash过程 (1 ...
- JDK1.7和JDK1.8中HashMap是线程不安全的,并发容器ConcurrentHashMap模型
一.HashMap是线程不安全的 前言 只要是对于集合有一定了解的一定都知道HashMap是线程不安全的,我们应该使用ConcurrentHashMap.但是为什么HashMap是线程不安全的呢,之前 ...
- Day1、为什么JDK1.8中HashMap从头插入改成尾插入
目录 Day1.为什么JDK1.8中HashMap从头插入改成尾插入 存储方式 静态常量 插入元素 扩容 拓展问题 1.为什么JDK1.8采用红黑树存储Hash冲突的元素? 2.为什么在长度小于8时使 ...
- JDK1.7中HashMap底层实现原理
JDK1.7中HashMap底层实现原理 一.数据结构 HashMap中的数据结构是数组+单链表的组合,以键值对(key-value)的形式存储元素的,通过put()和get()方法储存和获取对象. ...
- jdk1.8中HashMap扰动函数及数组长度为什么是2的n次方介绍
文章目录 前言 一.什么是二进制? 二.计算机采用二进制的原因 三.十进制与二进制相互转换 十进制转成二进制 二进制转换为十进制 与.或.异或运算 按位异或 按位与运算 按位或运算 Jdk1.8中Ha ...
- 七、JDK1.7中HashMap扩容机制
导读 前面文章一.深入理解-Java集合初篇 中我们对Java的集合体系进行一个简单的分析介绍,上两篇文章二.Jdk1.7和1.8中HashMap数据结构及源码分析 .三.JDK1.7和1.8Hash ...
- 八、JDK1.8中HashMap扩容机制
导读 前面文章一.深入理解-Java集合初篇 中我们对Java的集合体系进行一个简单的分析介绍,上两篇文章二.Jdk1.7和1.8中HashMap数据结构及源码分析 .三.JDK1.7和1.8Hash ...
- 出现无效字符_网站出现死链的原因分析 - 最蜘蛛池租用
原出处:最蜘蛛池 原文链接:网站出现死链的原因分析 - 最蜘蛛池 死链接是无效链接,外链是seo日常工作的重要组成部分.死链是网站建设中的一个专业术语.它是指那些不能输入的网页链接.在日常的网站操作中 ...
最新文章
- Exchange server 2013(十二)IRM故障排除
- 附件中可能包含对计算机有害的病毒.附件可能无法正确显示,广西成人高校计算机实用基础统考理论试题(A卷)...
- linux终端python自动提示
- linux rm 命令删除文件恢复_【Linux】恢复误删除的文件或目录
- 下载文件HTTP请求及处理过程
- 蜀门Online 简单打怪脚本(vbs)
- 计算机应届生面试,计算机应届生面试技巧
- LAMP部署phpadmin
- 【前端学习项目】web前端#001网页点名器(html+css+js实现用户交互)
- 一个屌丝程序员的青春(三三)
- 助力企业数字化转型 | 斑羚在线、环宇数通、乘云科技入选阿里云原生合作伙伴计划
- webpack 打包报错:Can't resolve '.\dist\bundle.js' in 'E:\vivian....'
- php怎么改字体大小,phpstorm修改字体和大小
- 二十四进制 加法计数器 并用数码管显示
- php excel下载打不开了,php下载excel无法打开的解决方法_PHP教程
- 图书管理系统——C语言版
- 锁存器、触发器、寄存器
- cadence allegro16.6 pcb文件转pads pcb文件方法教程
- 图片上添加文字及图片
- 日历制作视频教程下载
热门文章
- Oracle中decode函数用法解析以及常用场景
- 3dsmax怎么添加uv坐标_012:多层贴图UVWMAP(UV坐标)技术
- 大数据驱动社会治理的创新转向
- Wirecast Pro for Mac 9.0.0 网上直播软件 中文破解版下载
- 158万张图像的鉴黄数据集
- ArcGIS--GIS常用类型数据下载
- 好吧,CSS3 3D transform变换,不过如此!
- Android系统学习(37)---Android知识点及资料汇总
- 装机(一) ubuntu server 系统安装图文教程
- 31.区块链“不可能三角”