0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

为什么HashMap会产生死循环呢?

CodeSheep 来源:Java面试真题解析 2023-12-21 09:06 次阅读

HashMap 死循环是一个比较常见、比较经典的问题,在日常的面试中出现的频率比较高,今天这篇文章咱们就通过图解的方式,带大家彻底梳理和理解一下这个问题

前置知识

首先我们要了解一下为什么会有这个问题的发生?

死循环问题发生在 JDK 1.7 版本中,造成这个问题主要是由于 HashMap 自身的运行机制,加上并发操作,从而导致了死循环。在 JDK 1.7 中 HashMap 的底层数据实现是数组 + 链表的方式,如下图所示:efb8482e-9f9c-11ee-8b88-92fbcf53809c.png

而 HashMap 在数据添加时使用的是头插入,如下图所示:

efbc58b0-9f9c-11ee-8b88-92fbcf53809c.png

HashMap 正常情况下的扩容实现如下图所示:

efc7a058-9f9c-11ee-8b88-92fbcf53809c.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 节点,如下图所示:

efd4244a-9f9c-11ee-8b88-92fbcf53809c.png

死循环执行步骤2

死循环的第二步操作是,线程 T2 时间片用完进入休眠状态,而线程 T1 开始执行扩容操作,一直到线程 T1 扩容完成后,线程 T2 才被唤醒,扩容之后的场景如下图所示:

efe63bd0-9f9c-11ee-8b88-92fbcf53809c.png

从上图可知线程 T1 执行之后,因为是头插法,所以 HashMap 的顺序已经发生了改变,但线程 T2 对于发生的一切是不可知的,所以它的指向元素依然没变,如上图展示的那样,T2 指向的是 A 元素,T2.next 指向的节点是 B 元素。

死循环执行步骤3

当线程 T1 执行完,而线程 T2 恢复执行时,死循环就建立了,如下图所示:

eff47b82-9f9c-11ee-8b88-92fbcf53809c.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 替代。







审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 多线程
    +关注

    关注

    0

    文章

    277

    浏览量

    19888
  • JDK
    JDK
    +关注

    关注

    0

    文章

    80

    浏览量

    16567
  • hashmap
    +关注

    关注

    0

    文章

    14

    浏览量

    2269

原文标题:阿里二面:为什么HashMap会产生死循环

文章出处:【微信号:CodeSheep,微信公众号:CodeSheep】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    关于死循环语句

    do{..........} while(1) 和for(;;)[..............]这两个语句都代表死循环吧都是一样的意思吧!
    发表于 09-26 17:37

    为什么STM32仿真调试时会进入SystemInit死循环

    为什么STM32仿真调试时会进入SystemInit死循环?怎样去解决这个问题
    发表于 11-10 07:20

    外部中断函数初始化,执行的时候进入死循环是为什么?

    外部中断函数初始化,执行的时候进入死循环是为什么?
    发表于 11-25 08:10

    你怎么样用C语言编写死循环

    嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环?  一、while(1) { }没有划定初始化、更新区域的代码块(位置)。这两项代码的书写,就由作者来随意设置(完成)。后人接手程序,就要
    发表于 12-15 07:20

    死锁是什么?产生死锁的主要原因有哪些

    锁,就会造成系统死锁。产生死锁的三大主要原因:①系统资源不足②进程运行推进的顺序不合适③资源分配不当死锁的产生四个必要条件:①互斥条件:进程对所分配到的资源不允许其他进程访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源。②环路等待条件(
    发表于 12-22 07:34

    如何去处理嵌入式软件产生死锁的情况

    嵌入式软件产生死锁的必要条件及原因有哪些?如何去处理嵌入式软件产生死锁的情况
    发表于 12-24 06:12

    怎么样用C语言去编写嵌入式系统中的死循环

    怎么样用C语言去编写嵌入式系统中的死循环?关键字volatile有什么含义吗?
    发表于 12-24 07:46

    RT-Thread如何去发现该线程已经进入异常的死循环

    各位大佬,假在某个线程的执行代码的异常执行流中,如else处理中写了while(1)这种死循环代码,rt-thread如何去发现该线程已经进入异常的死循环?求指教。
    发表于 10-18 09:57

    关于Java HashMap的认知

    HashMap详解 HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接口的常用实现类,HashSet
    发表于 09-27 16:34 0次下载
    关于Java <b class='flag-5'>HashMap</b>的认知

    为什么单片机的程序必须是死循环

    为何单片机的程序必须是死循环?!!这个问题困扰了我好久,然而答案却是这个样子的!单片机没有操作系统,不像电脑有Windows,程序运行与结束有操作系统管理。单片机的程序是不能结束的,否则会使单片机系统出现不确定的状态;一般编译自己加上
    发表于 07-05 17:41 0次下载
    为什么单片机的程序必须是<b class='flag-5'>死循环</b>

    为什么单片机的主程序是死循环

    任何一个可用程序都必然是死循环程序,这不仅仅是指单片机程序。因为任何微处理器系统一旦开机,系统都在处理内部事件和外设响应,这个过程是一个循环过程,除非关机才能结束这个死循环程序。因此,对于单片机编程必须注意以下几点
    发表于 07-15 17:38 5256次阅读

    单片机的死循环有什么作用

    单片机是可编程器件,在使用时需要编写满足需求的程序。其C语言程序在各个端口、配置初始化完成后,进入一个死循环,一般用while(1){;}的形式。初始化完成后,单片机就在死循环内一遍又一遍的执行程序逻辑。复位后,就从头开始,初
    发表于 08-09 17:01 5650次阅读
    单片机的<b class='flag-5'>死循环</b>有什么作用

    如何避免Xil_Assert系列宏导致的死循环的情况

    在调试模式下,Xil_Assert系列宏会调用Xil_Assert来检查参数是否正常。如果不正常,缺省情况下,没有打印,进入死循环。 通过调用void Xil_AssertSetCallback
    的头像 发表于 12-02 16:20 4099次阅读
    如何避免Xil_Assert系列宏导致的<b class='flag-5'>死循环</b>的情况

    Too many open files错误导致服务器死循环

    在服务器编程中,经常会遇到 Too many open files 这个报错,而且这个报错如果处理不好,很有可能导致服务器死循环
    的头像 发表于 05-23 09:08 2458次阅读
    Too many open files错误导致服务器<b class='flag-5'>死循环</b>

    聊聊MCU死循环,用for(;;)还是while(1)?

    首先,问大家一个问题:你们写单片机程序【死循环】时,喜欢用for(;;)还是while(1)?快来为你喜欢用的【死循环】打call,评论区等你哦~一位工程师发现,国外工程师在给demo在做死循环时用
    的头像 发表于 04-29 08:10 1092次阅读
    聊聊MCU<b class='flag-5'>死循环</b>,用for(;;)还是while(1)?