三分钟轻松搞懂 HashMap 死循环问题!

开发 前端
HashMap 死循环发生在 JDK 1.7 版本中,形成死循环的原因是 HashMap 在 JDK 1.7 使用的是头插法,头插法 + 链表 + 多线程并发 + HashMap 扩容,这几个点加在一起就形成了 HashMap 的死循环。

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面试真题解析
相关推荐

2024-01-16 07:46:14

FutureTask接口用法

2024-01-12 07:38:38

AQS原理JUC

2023-12-04 18:13:03

GPU编程

2021-04-20 13:59:37

云计算

2023-12-27 08:15:47

Java虚拟线程

2022-02-17 09:24:11

TypeScript编程语言javaScrip

2023-12-23 18:04:40

服务Eureka工具

2021-12-17 07:47:37

IT风险框架

2009-11-05 16:04:19

Oracle用户表

2021-02-03 14:31:53

人工智能人脸识别

2020-06-29 07:42:20

边缘计算云计算技术

2022-05-23 08:35:43

粘包半包数据

2009-11-09 12:55:43

WCF事务

2023-12-22 09:37:13

二分查找数组数据库

2020-07-21 07:42:29

数据库信息技术

2023-08-14 09:16:26

消息存储磁盘

2020-08-17 17:20:36

pythonJAVA代码

2023-08-01 09:01:51

Broker• 事务消息selector

2024-02-22 07:37:37

对象JVM内存

2018-03-29 10:13:54

物联网协议MQTT
点赞
收藏

51CTO技术栈公众号