为什么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年就顺势搭上容器化这趟…

python字符串find_Python字符串| 带示例的find()方法

python字符串findString.find()方法 (String.find() Method) find() is an inbuilt method of python, it is used to check whether a sub-string exists in the string or not. If sub-string exists, the method returns the lowest index of the sub-string, if sub-string…

.sdp文件格式介绍

最近做RTSP流播放,需要了解.sdp这种会话描述的文件格式,当然,里面的具体语法有SDP解析器来分析。但是我需要大概了解一些字段的意思,它是文本描述的,采用key value的形式描述。 https://en.wikipedia.org/wiki/Session…

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

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

lambda python_Python | Lambda和filter()与示例

lambda pythonThe filter() function is used to filter the elements from given iterable collection based on applied function. filter()函数用于根据应用函数从给定的可迭代集合中过滤元素。 Example: 例: Given a list of integers and we have to filter …

浅谈 OneAPM 在 express 项目中的实践

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

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

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

stl swap函数_C ++ STL | vector :: swap()函数与示例

stl swap函数C STL vector :: swap()函数 (C STL vector::swap() function) vector::swap() function is used to swap/exchange the content of two vectors with the same type, their sizes may differ. vector :: swap()函数用于交换/交换相同类型的两个向量的内容&#x…

HDFS DataNode 设计实现解析

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

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

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

scala 空列表_如何在Scala中展平列表列表?

scala 空列表Flattening of List is converting a list of multiple List into a single List. To flatten List of List in Scala we will use the flatten method. 扁平化列表是将多个列表的列表转换为单个列表。 为了在Scala中扁平化List列表,我们将使用flatten方…

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

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

Automation Test in Maya Plugin Development

现状和问题- 开发插件的功能A的时候随手建立场景, 测试插件的功能A. 测试通过后,测试场景就被丢掉.- 发现插件的功能A有bug时, 修改代码, 然后随手建立场景, 测试bug. 测试通过后,测试场景就被丢掉.- 添加功能B, 测试功能B通过后, 在使用的时候发现之前的功能A却产生了bug, 应该…

scala集合中添加元素_如何在Scala中将元素添加到列表中?

scala集合中添加元素In Scala, lists are immutable data structures in which adding new elements is not allowed. So, here we will solve this problem that is generally done in functional programming paradigms. 在Scala中,列表是不可变的数据结构&#…

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

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

软件工程 质量问题_软件质量| 软件工程

软件工程 质量问题软件质量 (Software Quality) Software Quality is the degree of agreement too direct or indirect requirements and assumptions. Software quality is determined as a field of study and practice that describes the sensible traits of software pro…

为什么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调用,还能支持微服务间的调用,负载均衡和熔断限…