HashMap多线程下发生死循环的缘由

概述html


大神陈皓已经在疫苗:JAVA HASHMAP的死循环一文中详细描述了HashMap多线程下产生死循环的缘由,我仔细研读了这篇大做,作了一些笔记,加上本身的一些理解
整理出一些信息,发出来与你们交流交流。算法


HashMap存储的数据结构shell


陈皓在Hash表数据结构这一节提到了HashMap的数据结构以及扩容问题,关于这一点我以前写过的
HashMap的put和get方法原理HashMap扩容已经有详细的描述了。数组


多线程rehash的时候如何形成闭环链表数据结构


rehash源代码
多线程

这里写图片描述
这里写图片描述

这里写图片描述
这里写图片描述


正常的rehash过程并发


数据准备
在size=2的HashMap中按照顺序添加5, 7, 3这三个key,假设按照mod 2的算法来计算元素数组下标,那么key 5,7,3都会落在下标为1的数组桶中(发生hash冲突),以下图:
.net

这里写图片描述
这里写图片描述

把HashMap的size扩容为4后,rehash的过程线程

注意,发生hash冲突的5,7,3虽然都是在同一个链表中,可是每一个元素都得走rehash的过程,由于HashMap扩容后,这几个元素就未必都是在同一个链表中了3d

一、第一个是处理3这个key,先把key为3这个元素的next设置为空,并计算它在新数组中的下标,并存到新下标对应桶中,以下图:

这里写图片描述
这里写图片描述

二、第二个是处理7这个key,按照上面的约定,在新数组中3和7这个两个key仍是发生了hash冲突,那么按照HashMap发生冲突的处理代码,链表的第一个元素存储的是最新插入的7,而后next指向3,以下图:

这里写图片描述
这里写图片描述

三、第三个是处理5这个key,以下图:

这里写图片描述
这里写图片描述

到这里一次正常rehash过程走完了,最后三个key的存储状况以下图:

这里写图片描述
这里写图片描述


并发下的rehash过程


当两个并发线程thread1和thread2都同时进入到transfer时,也便是,恰好thread1和thread2都要对HashMap进行扩容,万一这个时候thread1执行下面的代码时,被线程调度器挂起了,而thread2则正常的把扩容的操做作完,以下图:

这里写图片描述
这里写图片描述

那这个时候,容器的数据存储状况以下:
对于thread1
这里写图片描述
这里写图片描述

对于thread2

这里写图片描述
这里写图片描述

这个时候,thread1拥有执行权限了,则继续它的扩容操做,等thread1扩容完后就产生了一个环形链表了(注意这里省略了一些步骤,不太明白的,则能够看我以前写的HashMap的put和get方法原理HashMap扩容)

这里写图片描述
这里写图片描述

这个时候,若是有个get请求,就有可能发生死循环,一直在链表中绕来绕去的,无法终止。


原文连接


HashMap多线程下发生死循环的缘由

相关文章
相关标签/搜索