写点什么

1-7 中 HashMap 死循环分析,透彻解析

发布于: 2021 年 09 月 01 日

现在 hashmap 中有三个元素,Hash 表的 size=2, 所以 key = 3, 7, 5,在 mod 2 以后都冲突在 table[1]这里了。



按照方法中的代码



对 table[1]中的链表来说,进入 while 循环,此时 e=key(3),那么 next=key(7),经过计算重新定位 e=key(3)在新表中的位置,并把 e=key(3)挂在 newTable[3]的位置




这样循环下去,将 table[1]中的链表循环完成后,于是 HashMap 就完成了扩容



并发下的扩容

上面都是单线程下的扩容,当多线程进行扩容时,会是什么样子呢?


初始的 HashMap 还是:



我们现在假设有两个线程并发操作,都进入了扩容操作, 我们以颜色进行区分两个线程。



回顾我们的扩容代码,我们假设,线程 1 执行到 Entry<K,V> next = e.next;时被操作系统调度挂起了,而线程 2 执行完成了扩容操作



于是,在线程 1,2 看来,就应该是这个样子



接下来,线程 1 被调度回来执行:


1)



2)



3)



4)



5)



6)



7)



循环列表产生后,一旦线程 1 调用 get(11,15 之类的元素)时,就会进入一个死循环的情况,将 CPU 的消耗到 100%。

总结

HashMap 之所以在并发下的扩容造成死循环,是因为,多个线程并发进行时,因为一个线程先期完成了扩容,将原的链表重新散列到自己的表中,并且链表变成了倒序,后一个线程再扩容时,又进行自己的散列,再次将倒序链表变为正序链表。于是形成了一个环形链表,当表中不存在的元素时,造成死循环。


虽然在 JDK1.8 中,Java 的开发小组修正了这个问题,但是 HashMap 始终存在着其他的线程安全问题。所以在并发情况下,我们应该使用 HastTable 或者 ConcurrentHashMap 来代替 HashMap。


你的赞和关注是我继续创作的动力~

最后

由于细节内容实在太多了,为了不影响文章的观赏性,只截出了一部分知识点大致的介绍一下,每个小节点里面都有更细化的内容!



需要这份文档的朋友可以帮忙点个赞,点击下方神秘超链接,就可以免费获取到了,还有小编准备的一份 Java 进阶学习路线图(Xmind)以及来年金三银四必备的一份《Java 面试必备指南》

资料领取链接:Java进阶学习路线图(Xmind)+《Java面试必备指南》


用户头像

VX公众号:编程进阶路 2020.11.28 加入

还未添加个人简介

评论

发布
暂无评论
1-7中HashMap死循环分析,透彻解析