为什么HashMap会产生死循环?

7ea10c9444a7efee5a09d4264391a122.png

作者:磊哥

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

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

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

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

前置知识

死循环问题发生在 JDK 1.7 版本中,造成这个问题主要是由于 HashMap 自身的运行机制,加上并发操作,从而导致了死循环。在 JDK 1.7 中 HashMap 的底层数据实现是数组 + 链表的方式,如下图所示:05f7b8cc3289acc8a297baac6e6ef4c2.png而 HashMap 在数据添加时使用的是头插入,如下图所示:d4176b4c4435d5f02a29c8b5bdc01af2.pngHashMap 正常情况下的扩容实现如下图所示:59e2a37bef019a920ed03e10a1b80c2a.png旧 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 节点,如下图所示:2d74b282d530c3d2eeb2ccdf5e26ad7c.png

死循环执行步骤2

死循环的第二步操作是,线程 T2 时间片用完进入休眠状态,而线程 T1 开始执行扩容操作,一直到线程 T1 扩容完成后,线程 T2 才被唤醒,扩容之后的场景如下图所示:307b2f659636ca3222a419c02df59389.png从上图可知线程 T1 执行之后,因为是头插法,所以 HashMap 的顺序已经发生了改变,但线程 T2 对于发生的一切是不可知的,所以它的指向元素依然没变,如上图展示的那样,T2 指向的是 A 元素,T2.next 指向的节点是 B 元素。

死循环执行步骤3

当线程 T1 执行完,而线程 T2 恢复执行时,死循环就建立了,如下图所示:466f2eaf1f738dd0c3afacba1b5f239c.png因为 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面试真题解析

42312ef596f34e645966015524884e94.gif

往期推荐

00ce7c80f80ca29a58aed260c774dde0.png

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


8cd8f11d8eeb586b957307df8294be32.png

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


32e3ebd9c7367621ecacf6b39b6aa48a.png

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


53f6388fc481d5ebb933cd0337ccc735.png

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


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544306.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iOS的自动化测试

2019独角兽企业重金招聘Python工程师标准>>> iOS的自动化测试:http://www.360doc.com/content/13/1225/22/1912775_340124906.shtml 转载于:https://my.oschina.net/CeShiXiaoSongShu/blog/496660

为什么阿里全面推动 K8S 落地,咬紧牙关也要搞云原生?

身为让容器应用实现大规模工业生产的一大功臣,过去几年,Kubernetes 势头迅猛,BAT、京东、美团、字节都走上了全域容器化部署以及云原生架构的康庄大道。而作为支撑阿里万亿级应用背后的核心,阿里云早在2016年就顺势搭上容器化这趟…

Spring Cloud Alibaba Nacos路由策略之保护阈值!

作者 | 磊哥来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)在 Nacos 的路由策略中有 3 个比较重要的内容:权重、保护阈值和就近访问。因为这 3 个内容都是彼此独立的&#…

浅谈 OneAPM 在 express 项目中的实践

【编者按】OneAPM 运营团队,近日在 github 上发现了一篇文章,特别奉献给大家。本文作者王宇先生从2015年年初就开始使用我们的产品,也是OneAPM 的忠实用户。 OneAPM 是一个优秀的性能监控平台。为什么我们要使用性能监控呢? 并不是…

【万字长文】Spring Cloud Alibaba 开箱即用!

互联网时代,面对复杂业务,讲究 分而治之。将一个大的单体系统拆分为若干个微服务,保证每个系统的职责单一,可以垂直深度扩展。但是一个个独立的微服务像一座座孤岛,如何将他们串联起来,才能发挥最大价值。这…

HDFS DataNode 设计实现解析

前文分析了 NameNode,本文进一步解析 DataNode 的设计和实现要点。 文件存储 DataNode 正如其名是负责存储文件数据的节点。HDFS 中文件的存储方式是将文件按块(block)切分,默认一个 block 64MB(该大小可配置&#xff…

芭比扣了!Nacos中服务删除不了,肿么办?

作者 | 磊哥来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)前两天遇到了一个问题,Nacos 中的永久服务删除不了,折腾了一番,最后还是顺利解决了。以下…

Spring Cloud OpenFeign夺命连环9问,这谁受得了?

1、前言前面介绍了Spring Cloud 中的灵魂摆渡者Nacos,和它的前辈们相比不仅仅功能强大,而且部署非常简单。今天介绍一款服务调用的组件:OpenFeign,同样是一款超越先辈(Ribbon、Feign)的狠角色。文章目录如下…

玩转Nacos参数配置!多图勿点

作者 | 磊哥来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)Nacos 中的参数有很多,如:命名空间、分组名、服务名、保护阈值、服务路由类型、临时实例等&#xff…

为什么wait/notify必须要和synchronized一起使用?

作者 | 磊哥来源 | Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)在多线程编程中,wait 方法是让当前线程进入休眠状态,直到另一个线程调用了 notify 或 notify…

Magento Add Fee or Discount to Order Totals

2019独角兽企业重金招聘Python工程师标准>>> In this tutorial, we will see how to add new line item to magento order totals. What this means is that, how to add an additional Fee or Discount, or any kind of charge to order total of the magento chec…

再见 Feign!推荐一款微服务间调用神器,跟 SpringCloud 绝配!

在微服务项目中,如果我们想实现服务间调用,一般会选择Feign。之前介绍过一款HTTP客户端工具Retrofit,配合SpringBoot非常好用!其实Retrofit不仅支持普通的HTTP调用,还能支持微服务间的调用,负载均衡和熔断限…

Spring Cloud Alibaba Nacos 的 2 种健康检查机制!

作者 | 磊哥来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)Spring Cloud Alibaba Nacos 作为注册中心不止提供了服务注册和服务发现功能,它还提供了服务可用性监测的机制。…

Python之包管理工具

在Python环境中已经有很多成熟的包,可以通过安装这些包来扩展我们的程序。 例如,很多时候Python开发人员都会去PyPI网站去查找自己想要使用的包,然后进行安装。PyPI ( Python Package Index)是获得第三方 Python 软件包…

为什么wait和notify必须放在synchronized中?

作者 | 磊哥来源 | Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)在多线程编程中,wait 方法是让当前线程进入休眠状态,直到另一个线程调用了 notify 或 notify…

聊聊并发编程的10个坑

前言对于从事后端开发的同学来说,并发编程肯定再熟悉不过了。说实话,在java中并发编程是一大难点,至少我是这么认为的。不光理解起来比较费劲,使用起来更容易踩坑。不信,让继续往下面看。今天重点跟大家一起聊聊并发编…

macbook终端使用记(二)终端快捷键

为什么80%的码农都做不了架构师?>>> Command K清屏 Command T新建标签 Command M最小化窗口 Command W 关闭当前标签页 Command S 保存终端输出 Command D 垂直分隔当前标签页 Command Shift D 水平分隔当前标签页 Command shift {或}向左/向…

颜值爆表!Redis 官方可视化工具来啦,功能真心强大!

最近逛了一下Redis官方网站,发现Redis不仅推出了很多新特性,而且还发布了一款可视化工具RedisInsight。试用了一下感觉非常不错,最关键的是能支持RedisJSON之类的新特性,这是第三方工具无法比拟的。今天带大家体验一下RedisInsigh…

20个响应式网页设计中的“神话”误区

关于响应式网页的重要性我们已经证实了很长时间了,现在是该把焦点放到如何做出好的响应式网页设计的时候了。一起来看看吧! 虽然很多人都在谈论响应式网页,但并不是每个人都知道他们在说什么。很多时候你看到网上的一些信息也在挑战你对响应式…

MySQL 索引失效的 15 种场景!

背景 无论你是技术大佬,还是刚入行的小白,时不时都会踩到Mysql数据库不走索引的坑。常见的现象就是:明明在字段上添加了索引,但却并未生效。前些天就遇到一个稍微特殊的场景,同一条SQL语句,在某些参数下生效…