Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Coudy Hou
JavaGuide
提交
51655d38
J
JavaGuide
项目概览
Coudy Hou
/
JavaGuide
与 Fork 源项目一致
从无法访问的项目Fork
通知
5
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
JavaGuide
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
51655d38
编写于
8月 24, 2018
作者:
S
Snailclimb
提交者:
GitHub
8月 24, 2018
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
更新题目:“HashMap 多线程操作导致死循环问题”并更改文首目录
上级
1e17f5db
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
11 addition
and
10 deletion
+11
-10
Java相关/这几道Java集合框架面试题几乎必问.md
Java相关/这几道Java集合框架面试题几乎必问.md
+11
-10
未找到文件。
Java相关/这几道Java集合框架面试题几乎必问.md
浏览文件 @
51655d38
...
...
@@ -5,10 +5,11 @@
> 3. HashMap的底层实现
> 4. HashMap 和 Hashtable 的区别
> 5. HashMap 的长度为什么是2的幂次方
> 6. HashSet 和 HashMap 区别
> 7. ConcurrentHashMap 和 Hashtable 的区别
> 8. ConcurrentHashMap线程安全的具体实现方式/底层具体实现
> 9. 集合框架底层数据结构总结
> 6. HashMap 多线程操作导致死循环问题
> 7. HashSet 和 HashMap 区别
> 8. ConcurrentHashMap 和 Hashtable 的区别
> 9. ConcurrentHashMap线程安全的具体实现方式/底层具体实现
> 10. 集合框架底层数据结构总结
...
...
@@ -76,22 +77,22 @@ JDK1.8 之前 HashMap 由 **数组+链表** 组成的(**“链表散列”**
## HashMap 多线程操作导致死循环问题
在多线程下,进行
put操作会导致hash map死循环,原因在于hashmap 的扩容resize方法,由于扩容是新建一个数组,复制原数据到数组,由于数组下标挂有链表,所以需要复制链表,多线程操作有可能导致环形链表,
复制链表过程如下:
以下模拟2个线程同时扩容。假设,当前
hashmap的空间为2(临界值为1),hashcode分别为0和1,在散列地址0处有元素A和B,这时候要添加元素C,C经过hash运算,得到散列地址为1,这时候由于超过了临界值,空间不够,需要调用resize
方法进行扩容,那么在多线程条件下,会出现条件竞争,模拟过程如下:
在多线程下,进行
put 操作会导致 HashMap 死循环,原因在于 HashMap 的扩容 resize()方法。由于扩容是新建一个数组,复制原数据到数组。由于数组下标挂有链表,所以需要复制链表,但是多线程操作有可能导致环形链表。
复制链表过程如下:
以下模拟2个线程同时扩容。假设,当前
HashMap 的空间为2(临界值为1),hashcode 分别为 0 和 1,在散列地址 0 处有元素 A 和 B,这时候要添加元素 C,C 经过 hash 运算,得到散列地址为 1,这时候由于超过了临界值,空间不够,需要调用 resize
方法进行扩容,那么在多线程条件下,会出现条件竞争,模拟过程如下:
线程一:读取到当前的
hashmap
情况,在准备扩容时,线程二介入
线程一:读取到当前的
HashMap
情况,在准备扩容时,线程二介入
![](
https://note.youdao.com/yws/public/resource/e4cec65883d9fdc24effba57dcfa5241/xmlnote/41aed567e3419e1314bfbf689e3255a2/192
)
线程二:读取
hashm
ap,进行扩容
线程二:读取
HashM
ap,进行扩容
![](
https://note.youdao.com/yws/public/resource/e4cec65883d9fdc24effba57dcfa5241/xmlnote/f44624419c0a49686fb12aa37527ee65/191
)
线程一:继续执行
![](
https://note.youdao.com/yws/public/resource/e4cec65883d9fdc24effba57dcfa5241/xmlnote/79424b2bf4a89902a9e85c64600268e4/193
)
这个过程为,先将
A复制到新的hash表中,然后接着复制B到链头(A的前边:B.next=A),本来B.next=null,到此也就结束了(跟线程二一样的过程),但是,由于线程二扩容的原因,将B.next=A,所以,这里继续复制A,让
A.next=B,由此,环形链表出现:B.next=A; A.next=B
这个过程为,先将
A 复制到新的 hash 表中,然后接着复制 B 到链头(A 的前边:B.next=A),本来 B.next=null,到此也就结束了(跟线程二一样的过程),但是,由于线程二扩容的原因,将 B.next=A,所以,这里继续复制A,让
A.next=B,由此,环形链表出现:B.next=A; A.next=B
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录