(转)并发场景下HashMap死循环导致CPU100%的问题

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介:     问题的核心点在于多线程进行扩容的时候每个线程会生成一个新的hashtab对象,线程A生成新的hashtab以后,线程B在线程A新生成的hastab上进行操作会造成死循环。

    问题的核心点在于多线程进行扩容的时候每个线程会生成一个新的hashtab对象,线程A生成新的hashtab以后,线程B在线程A新生成的hastab上进行操作会造成死循环。

    可以参考jdk1.7的hashmap扩容问题的文章。


核心摘录


正常的ReHash的过程

画了个图做了个演示。

我假设了我们的hash算法就是简单的用key mod 一下表的大小(也就是数组的长度)。

最上面的是old hash 表,其中的Hash表的size=2, 所以key = 3, 7, 5,在mod 2以后都冲突在table[1]这里了。

接下来的三个步骤是Hash表 resize成4,然后所有的 重新rehash的过程


img_5e5fa5460c618039690b7a736cbdf12f.png
串行rehash


并发下的Rehash

1)假设我们有两个线程。我用红色和浅蓝色标注了一下。

我们再回头看一下我们的 transfer代码中的这个细节:

img_19233ede12aeb66b0373e68c0595e5ba.png
扩容代码

而我们的线程二执行完成了。于是我们有下面的这个样子。


img_9d0405bdac6586641a14742c31a6d00a.png

注意,因为Thread1的 e 指向了key(3),而next指向了key(7),其在线程二rehash后,指向了线程二重组后的链表。我们可以看到链表的顺序被反转后。

2)线程一被调度回来执行。

先是执行 newTalbe[i] = e;

然后是e = next,导致了e指向了key(7),

而下一次循环的next = e.next导致了next指向了key(3)


img_4ea4930fb2b87d0553c3560f060e5ef2.png

3)一切安好。

线程一接着工作。把key(7)摘下来,放到newTable[i]的第一个,然后把e和next往下移


img_96168bc9052094192ee23419dc3b0794.png

4)环形链接出现。

e.next = newTable[i] 导致  key(3).next 指向了 key(7)

注意:此时的key(7).next 已经指向了key(3), 环形链表就这样出现了。


img_3e6aee62745527b5bc9a720ee34d5e81.png

于是,当我们的线程一调用到,HashTable.get(11)时,悲剧就出现了——Infinite Loop。

此时两个线程put完毕,线程二先完成rehash,之后再线程一rehash,线程一最终put的链形成了闭环,但是这两个线程没有死循环,只是后来get的线程如果进入这个闭环链,就死循环了,并且进入的线程越多,CPU消耗的越大,最终到达100%

参考文章

jdk1.7: https://blog.csdn.net/c929833623lvcha/article/details/8924414?utm_source=jiancool

jdk1.8: https://blog.csdn.net/u012961566/article/details/72963157

目录
相关文章
|
Web App开发 Java 测试技术
ChaosBlade常见问题之演练场景页面乱码cpu使用率图片显示不出来如何解决
ChaosBlade 是一个开源的混沌工程实验工具,旨在通过模拟各种常见的硬件、软件、网络、应用等故障,帮助开发者在测试环境中验证系统的容错和自动恢复能力。以下是关于ChaosBlade的一些常见问题合集:
342 0
|
开发框架 并行计算 算法
揭秘Python并发神器:IO密集型与CPU密集型任务的异步革命,你竟还傻傻分不清?
揭秘Python并发神器:IO密集型与CPU密集型任务的异步革命,你竟还傻傻分不清?
326 4
|
监控 并行计算 数据处理
构建高效Python应用:并发与异步编程的实战秘籍,IO与CPU密集型任务一网打尽!
在Python编程的征途中,面对日益增长的性能需求,如何构建高效的应用成为了每位开发者必须面对的课题。并发与异步编程作为提升程序性能的两大法宝,在处理IO密集型与CPU密集型任务时展现出了巨大的潜力。今天,我们将深入探讨这些技术的最佳实践,助你打造高效Python应用。
358 0
|
存储 监控 算法
taosd 写入与查询场景下压缩解压及加密解密的 CPU 占用分析
在当今大数据时代,时序数据库的应用越来越广泛,尤其是在物联网、工业监控、金融分析等领域。TDengine 作为一款高性能的时序数据库,凭借独特的存储架构和高效的压缩算法,在存储和查询效率上表现出色。然而,随着数据规模的不断增长,在保证数据安全性和存储效率的同时,如何优化 CPU 的资源占用,成为了一个值得深入讨论的问题。
332 1
|
Java 调度
HashMap为什么会死循环?
本文分析了在Java中HashMap导致死循环的原因,主要由于在JDK 1.7及之前版本中,多线程环境下进行扩容操作时,头插法导致的链表反转,以及线程调度问题,从而形成循环链表。
1831 1
HashMap为什么会死循环?
|
设计模式 安全 Java
HashMap底层原理:数据结构+put()流程+2的n次方+死循环+数据覆盖问题
假如有T1、T2两个线程同时对某链表扩容,他们都标记头结点和第二个结点,此时T2阻塞,T1执行完扩容后链表结点顺序反过来,此时T2恢复运行再进行翻转就会产生环形链表,即B.next=A;采用2的指数进行扩容,是为了利用位运算,提高扩容运算的效率。JDK8中,HashMap采用尾插法,扩容时链表节点位置不会翻转,解决了扩容死循环问题,但是性能差了一点,因为要遍历链表再查到尾部。例如15(即2^4-1)的二进制为1111,31的二进制为11111,63的二进制为111111,127的二进制为1111111。
HashMap底层原理:数据结构+put()流程+2的n次方+死循环+数据覆盖问题
|
开发框架 并行计算 .NET
脑洞大开!Python并发与异步编程的哲学思考:IO密集型与CPU密集型任务的智慧选择!
脑洞大开!Python并发与异步编程的哲学思考:IO密集型与CPU密集型任务的智慧选择!
308 1
|
并行计算 监控 数据处理
构建高效Python应用:并发与异步编程的实战秘籍,IO与CPU密集型任务一网打尽!
【7月更文挑战第16天】Python并发异步提升性能:使用`asyncio`处理IO密集型任务,如网络请求,借助事件循环实现非阻塞;`multiprocessing`模块用于CPU密集型任务,绕过GIL进行并行计算。通过任务类型识别、任务分割、避免共享状态、利用现代库和性能调优,实现高效编程。示例代码展示异步HTTP请求和多进程数据处理。
331 8
|
存储 算法 安全
HashMap常见面试题(超全面):实现原理、扩容机制、链表何时升级为红黑树、死循环
HashMap常见面试题:红黑树、散列表,HashMap实现原理、扩容机制,HashMap的jd1.7与jdk1.8有什么区别,寻址算法、链表何时升级为红黑树、死循环
|
算法 Java 程序员
解锁Python高效之道:并发与异步在IO与CPU密集型任务中的精准打击策略!
【7月更文挑战第17天】在数据驱动时代,Python凭借其优雅语法和强大库支持成为并发处理大规模数据的首选。并发与异步编程是关键,包括多线程、多进程和异步IO。对于IO密集型任务,如网络请求,可使用`concurrent.futures`和`asyncio`;CPU密集型任务则推荐多进程,如`multiprocessing`;`asyncio`适用于混合任务,实现等待IO时执行CPU任务。通过这些工具,开发者能有效优化资源,提升系统性能。
461 4