作者:磊哥

来源 | Java面试真题解析(ID:aimianshi666)

转载请联系授权(微信ID:GG_Stone)

面试合集:https://gitee.com/mydb/interview

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

前置知识

死循环问题发生在 JDK 1.7 版本中,造成这个问题主要是由于 HashMap 自身的运行机制,加上并发操作,从而导致了死循环。在 JDK 1.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 死循环发生在 JDK 1.7 版本中,形成死循环的原因是 HashMap 在 JDK 1.7 使用的是头插法,头插法 + 链表 + 多线程并发 + HashMap 扩容,这几个点加在一起就形成了 HashMap 的死循环,解决死锁可以采用线程安全容器 ConcurrentHashMap 替代。

是非审之于己,毁誉听之于人,得失安之于数。

公众号:Java面试真题解析

往期推荐

面试突击15:说一下HashMap底层实现?及元素添加流程?

面试突击14:方法重写和方法重载有什么区别?

面试突击13:方法优先调用可选参数还是固定参数?

面试系列12:为什么不同返回类型不算方法重载?

为什么HashMap会产生死循环?相关推荐

  1. java8 hashmap 死循环_踩坑了,JDK8中HashMap依然会死循环!

    作者:Aaron_涛 原文:blog.csdn.net/qq_33330687/article/details/101479385 是否你听说过JDK8之后HashMap已经解决的扩容死循环的问题,虽 ...

  2. HashMap 1.7 死循环过程

    "死锁"过程 为什么 hashmap底层数组大小为2的幂次 , 例如  初始化 16 计算hash值  时 (length-1)&(hash) 16-1  = 0000 1 ...

  3. 高并发下的 HashMap 为什么会死循环

    作者 | tech-bus.七十一 来源 | 程序员巴士 前言   HashMap并发情况下产生的死循环问题在JDK 1.7及之前版本是存在的,JDK 1.8 通过增加loHead头节点和loTail ...

  4. hashmap扩容时死循环问题

    废话不多说,大家都知道,hashmap不能用于多线程场景中,多线程下推荐使用concurrentHashmap! 但为什么多线程下不能使用hashmap那,主要原因就在于其的扩容机制. 文章是综合他人 ...

  5. 多线程环境下,HashMap为什么会出现死循环?

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/dingjianmin/ article/details/79780350 Java的HashMap是非线程安全的.多线程下应该 ...

  6. HashMap扩容死循环问题

    HashMap扩容死循环问题源码分析问题(jdk1.7) 一.首先hashmap单线程正常扩容 遍历每个数组,依次遍历每个数组的链表,根据头插法由原来的1,2,3 变为了3,2,1 二.hashmap ...

  7. HashMap 为什么线程不安全?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:developer cnblogs.com/develope ...

  8. HashMap 为什么会导致 CPU 100%?文章看不懂?

    来自:Java中文社群 无论是在实际工作中还是在面试中,HashMap 无疑是使用频率最高的知识点之一,所以我们需要搞懂每一个关于 HashMap 的知识点才行. 哈喽,大家好,我是老王,欢迎来到 J ...

  9. 都说 HashMap 是线程不安全的,到底体现在哪儿?

    前言:我们都知道HashMap是线程不安全的,在多线程环境中不建议使用,但是其线程不安全主要体现在什么地方呢,本文将对该问题进行解密. 1.jdk1.7中的HashMap 在jdk1.8中对HashM ...

最新文章

  1. Linux0.00内核为什么要自己设置0x80号陷阱门来调用write_char过程?
  2. Error: /usr/lib64/libstdc++.so.6: version `CXXABI_1.3.8‘ not found (required by /usr/anaconda3/bin/)
  3. 读取javascript脚本的正则表达式
  4. 详解@Builder用法
  5. Java ArrayList的不同排序方法
  6. android136 360 拖拽
  7. linux curl 特殊字符,遇到问题--curl--- url参数中有+、空格、=、%、、#等特殊符号的导致传参不全 | 易学教程...
  8. 【干货】TCP/IP协议三次握手四次挥手
  9. 运维基础--用户的权限管理
  10. 在C#中解析命令行参数的最佳方法? [关闭]
  11. mariadb启动时报错Job for mariadb.service failed because the control process exited with error code....
  12. 软件实习项目4——校园一卡通管理系统(实验准备与设计)
  13. java毕业设计外卖管理系统mybatis+源码+调试部署+系统+数据库+lw
  14. Google官方架构MVI
  15. 利用 Python 爬取58同城品牌公寓(附带租房指南)
  16. 转战物联网·基础篇10-物联网架构硬件端的特点及行业应用,对初创项目的选型建议
  17. iOS最新面试题(一)
  18. Vue中使用swiper构建简易轮播图
  19. 计算机向u盘拷贝速度慢,U盘复制速度慢的解决措施
  20. 电子商务系统的设计与实现(十一):数据库设计

热门文章

  1. awk教程入门与实例练习(二)
  2. C#组成考题字符串【C#】
  3. 搞懂 Java HashMap 源码
  4. java.util.Date和java.sql.Date 一点区别
  5. 读书笔记《集体智慧编程》Chapter 2 : Make Recommendations
  6. PHP5.5四种序列化性能对比
  7. ACM - 第6章 数据结构基础(2)
  8. Follow Me:CCIE RS--使用小凡模拟器搭建的CCIE拓扑图
  9. winpe装双系统linux_使用syslinux在u盘安装pubbylinux和winpe双系统
  10. 伪代码书写规范_C++代码书写规范(推荐新手程序员)