首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

HashMap并发造成死循环问题解析

HashMap死循环 首先小伙伴要明确:死循环问题在JDK 1.8 之前是存在的,JDK 1.8 通过增加loHead和loTail进行了修复。...在JDK 1.7及之前 HashMap并发情况下导致循环问题,致使服务器cpu飙升至100%,那么今天就来解析一下线程不安全的HashMap在高并发的情况下是如何造成死循环的。...要探究hashmap死循环的原因 首先要知道hashmap的源码 这样才能从根本上对hashmap进行理解 。 首先hashmap进行元素的插入,在元素个数达到阀值: ?...添加元素达到阀值后对hashmap进行扩容,走reaize方法,在对hashmap进行扩容,又会调用一个transfer对旧的hashmap中的元素进行转移,那么我们今天要探究的死循环问题 就是发生在这个方法里的...那么当多线程(A、B线程)同时访问我们这段代码: ?

2.4K10
您找到你想要的搜索结果了吗?
是的
没有找到

链表的学习:链表的和尾以及HashMap中链表结点的插入方式

本文将重点介绍单链表数据结构,然后通过代码实现单链表的和尾。 单链表的介绍 我们都知道数组是需要一块连续的内存空间来存储的,而链表只需要零散的内存碎片,通过指针相连即可。...当初始化链表,默认头结点为null。作为一个基地址。并将current节点赋值给head。 插入节点 尾的逻辑比较简单,就是遍历链表,条件是current.next!...插入的逻辑与尾法相反,只需要找到头结点,然后将要插入结点的next指针指向current结点。...中链表是还是尾 JDK1.7以前的版本 如果遍历链表都没法发现相应的key值的话,则会调用addEntry方法在链表添加一个Entry,重点就在于addEntry方法是如何插入链表的,addEntry...* table.length); } 这里构造了一个新的Entry对象(构造方法的最后一个参数传入了当前的Entry链表),然后直接用这个新的Entry对象取代了旧的Entry链表,可以猜测这应该是

77030

HashMap的为啥用尾?

一.那么关于遇到hash冲突时候这个数据是呢?还是尾呢?...关于HashMap链表插入问题,java8之前之前是 :就是说新来的值会取代原有的值,原有的值就顺推到链表中去,就像上面的例子一样,因为写这个代码的作者认为后来的值被查找的可能性更大一点,...使用会改变链表的上的顺序,但是如果使用尾,在扩容时会保持链表元素原本的顺序,就不会出现链表成环的问题了 Java8在同样的前提下并不会引起死循环,原因是扩容转移后前后链表顺序不变,保持之前节点的引用关系...那是必然不可以的,HashMap put/get方法都没有加同步锁,这里存在一个并发修改的问题,ConcurrentModifyExcption,所以线程安全还是无法保证。...关于本文中头详情可看码农届网红敖丙的原文https://juejin.im/user/59b416065188257e671b670a/posts 但是我觉得这篇文章写的比较简略,面向面试还行

1.7K20

HashMap 链表插入方式 → 为何改成尾 ?

链表元素的转移,还是采用的   链表成环     不管是元素的添加,还是数组扩容,只要涉及到 hash 冲突,就会采用将元素添加到链表中     上面讲了那么多,看似风平浪静,实则暗流涌动;...,维护了链表元素的原有顺序   在扩容法会改变链表中元素原本的顺序,以至于在并发场景下导致链表成环的问题,而尾,在扩容时会保持链表元素原本的顺序,就不会出现链表成环的问题 相关疑惑   1、...,为什么直到 1.8 才采用尾来替代     只有在并发情况下,才会出现链表成环的问题,多线程情况下,HashMap 本就非线程安全,这就相当于你在它的规则之外出了问题,那能怪谁?     ...,但是还是会有很多其他的并发问题,比如:上秒 put 的值,下秒 get 的时候却不是刚 put 的值;因为操作都没有加锁,不是线程安全的 总结   1、JDK 1.7 采用来添加链表元素,存在链表成环的问题...,1.8 中做了优化,采用尾来添加链表元素   2、HashMap 不管在哪个版本都不是线程安全的,出了并发问题不要怪 HashMap,从自己身上找原因 参考 HashMap为何从头插入改为尾插入

1.2K10

前置知识

在 JDK 1.7 中 HashMap 的底层数据实现是数组 + 链表的方式,如下图所示: 而 HashMap 在数据添加使用的是插入,如下图所示: HashMap 正常情况下的扩容实现如下图所示...: 旧 HashMap 的节点会依次转移到新 HashMap 中,旧 HashMap 转移的顺序是 A、B、C,而新 HashMap 使用的是,所以最终在新 HashMap 中的顺序是...死循环执行步骤1 死循环是因为并发 HashMap 扩容导致的,并发扩容的第一步,线程 T1 和线程 T2 要对 HashMap 进行扩容操作,此时 T1 和 T2 指向的是链表的结点元素 A,而 T1...,一直到线程 T1 扩容完成后,线程 T2 才被唤醒,扩容之后的场景如下图所示: 从上图可知线程 T1 执行之后,因为是,所以 HashMap 的顺序已经发生了改变,但线程 T2 对于发生的一切是不可知的...总结 HashMap 死循环发生在 JDK 1.7 版本中,形成死循环的原因是 HashMap 在 JDK 1.7 使用的是 + 链表 + 多线程并发 + HashMap 扩容,这几个点加在一起就形成了

71030

并发下的 HashMap 为什么会引起死循环???

今天研读Java并发容器和框架,看到为什么要使用ConcurrentHashMap,其中有一个原因是:线程不安全的HashMap, HashMap并发执行put操作时会引起死循环,是因为多线程会导致...HashMap的Entry链表形成环形数据结构,查找时会陷入死循环。...(1)当往HashMap中添加元素,会引起HashMap容器的扩容,原理不再解释,直接附源代码,如下: /** * * 往表中添加元素,如果插入元素之后,表长度不够,便会调用resize...并发,会引起死循环的根本原因所在,下面结合transfer的源代码,说明一下产生死循环的原理,先列transfer代码(这是里JDK7的源偌),如下: /** * Transfers...会陷入死循环

65610

为什么HashMap会产生死循环

HashMap在数据插入时又采用的是,也就是说新插入的数据会从链表的节点进行插入。 因此,HashMap正常情况下的扩容就是是这样一个过程。...我们来看,旧HashMap的节点会依次转移到新的HashMap中,旧HashMap转移链表元素的顺序是A、B、C,而新HashMap使用的是插入,所以,扩容完成后最终在新HashMap中链表元素的顺序是...因为HashMap扩容采用的是,线程T1执行之后,链表中的节点顺序发生了改变。但线程T2对于发生的一切还是不可知的,所以它指向的节点引用依然没变。...4、总结 HashMap死循环只发生在JDK1.7版本中,主要原因是JDK1.7中的HashMap,在 加 链表 加 多线程并发 加 扩容这几个情形累加到一起就会形成死循环。...在JDK1.8中,HashMap改成了尾,解决了链表死循环的问题。 以上就是关于HashMap死循环原因的分析。

62711

HashMap为什么存在线程不安全呢?

,然后再将新结点作为 bucket 的头部,并指向旧的结点,完成一次的操作。...另外,只有 JDK1.7 及以前的版本会存在死循环现象,在JDK1.8 中,resize()方式已经做了调整,使用两队链表,且都是使用的尾,及时多线程下,也顶多是从头结点再做一次尾,不会造成死循环...而JDK1.7能造成死循环,就是因为 resize()使用了,将原本的顺序做了反转,才留下了死循环的机会。...的扩容操作,重新定位每个桶的下标,并采用将元素迁移到新数组中。...继续执行头,将 b 变为链表的结点,同时 next 指针指向旧的节点 a,如下图: ? 此时,下一个结点e.next为 a 节点,不为 null,继续

78030

面试官:为什么 HashMap 并发时会引起死循环

今天研读 Java 并发容器和框架,看到为什么要使用 ConcurrentHashMap ,其中有一个原因是:线程不安全的HashMap, HashMap并发执行put操作时会引起死循环,是因为多线程会导致...HashMap的Entry链表形成环形数据结构,查找时会陷入死循环。...(1)当往HashMap中添加元素,会引起HashMap容器的扩容,原理不再解释,直接附源代码,如下: /** * * 往表中添加元素,如果插入元素之后,表长度不够,便会调用resize...并发,会引起死循环的根本原因所在,下面结合transfer的源代码,说明一下产生死循环的原理,先列transfer代码(这是里JDK7的源码),如下: /** * Transfers all...当操作完成,执行查找,会陷入死循环

32620

Hashmap1.7和1.8区别

Hashmap1.7和1.8 主要有四个区别,下面将一一说明 存储结构 在1.7版本中,HashMap使用数组+链表的方式实现,即当发生哈希冲突,会使用链表将冲突的元素串起来。...在1.8版本中,当链表长度超过一定阈值(默认为8),链表会转化为红黑树,以提高查找效率。 并发性 在1.7版本中,HashMap在多线程环境下存在并发问题,可能导致死循环。...在1.8版本中,HashMap引入了"锁分段"机制,将整个存储空间分成了多个段(默认为16段),每个段独立加锁,可以提高并发性能。...PUT插入方式 JDK1.7用的是,而JDK1.8及之后使用的都是尾,因为JDK1.7是用单链表进行的纵向延伸,当采用时会容易出现逆序且环形链表死循环问题。...但是在JDK1.8之后是因为加入了红黑树使用尾,能够避免出现逆序且链表死循环的问题。

17440

面试突击17:HashMap除了死循环还有什么问题?

1.死循环问题 死循环问题发生在 JDK 1.7 版本中,形成的原因是 JDK 1.7 HashMap 使用的是,那么在并发扩容可能就会导致死循环的问题,具体产生的过程如下流程所示。...使用的是,所以最终在新 HashMap 中的顺序是 C、B、A,也就是上图展示的那样。...1.1 死循环执行流程一 死循环是因为并发 HashMap 扩容导致的,并发扩容的第一步,线程 T1 和线程 T2 要对 HashMap 进行扩容操作,此时 T1 和 T2 指向的是链表的结点元素 A...时间片用完进入休眠状态,而线程 T1 开始执行扩容操作,一直到线程 T1 扩容完成后,线程 T2 才被唤醒,扩容之后的场景如下图所示: 从上图可知线程 T1 执行之后,因为是,所以 HashMap...的经典问题,其中死循环和数据覆盖是发生在并发添加元素,而无序问题是添加元素的顺序和查询的顺序不一致的问题,这些问题本质来说都是对 HashMap 使用不当才会造成的问题,比如在多线程情况下就应该使用

41220

对线面试官 - HashMap

数据插入过程采用的是一个。...派大星:HashMap在1.8之后就进行了升级优化,变成了一个又链表+ 数组+红黑树的一个数据结构,并且把原来的entry节点换成了Node节点,优化成了尾。...由于1.7之前的数组+链表的数据结构和头的原因导致了在并发情况下可能会出现死链的情况。...具体的表现形式为:当HashMap需要扩容的时候会将旧的HashMap的节点依次转移到新的HashMap中,假设旧的HashMap的链表是A、B、C,而新的HashMap由于采用的是所以最终新的HashMap...这个时候最大的问题是线程T2的指向还没有变,因为是,所以新的HashMap的顺序已经改变了。但对线程T2来说它是不知道的。所以它的指向元素没有发生改变。

13240

HashMap并发情况下为什么造成死循环

那么面试官就会紧接着问道,为什么hashmap不是线程安全的,会造成什么问题么?于是面试者就回答:HashMap并发情况下的put操作会造成死循环。...这时候就会被面试官问:HashMap并发为什么造成死循环? 很多面试者这时候就会一脸懵。没有过相关经验和深入的理解源码是很难回答这个问题的。...下面我们就通过HahMap源码来验证下,多线程并发put操作为何会生成环形链表,产生死循环。...HashMap并发执行put操作发生扩容,可能会导致节点丢失,产生环形链表等情况。 节点丢失,会导致数据不准 生成环形链表,会导致get()方法死循环。...知识拓展 在jdk1.7中,由于扩容使用,在并发可能会形成环状列表,导致死循环,在jdk1.8中改为尾,可以避免这种问题,但是依然避免不了节点丢失的问题。

1.7K10
领券