关注
首先要明确一点,HashMap形成环(并发死链)只会发生在jdk7及以前版本。在多个线程同时对容器进行扩容时会出现该现象。
HashMap在进行扩容时调用resize()方法,该方***创建一个新的Entry数组,再调用transfer()方法吧原数组上的元素转移到新创建的数组上。
由于jdk7及以前采用头插法,也就是说,新table中链表上元素的顺序和旧列表相反。
在多个线程同时执行扩容操作时,会造成链表成环。
Entry<K,V> next = e.next; // 1 处
e.next = newTable[i]; // 2 处
例如:假设 map 中初始元素,数组的[1]索引上的链表元素为[1] (1,35)->(35,16)->(16,null) 括号中前一个为链表的节点元素,后一个为其指向的下一个元素。
线程 a 执行到 1 处 ,此时局部变量 e 为 (1,35),而局部变量 next 为 (35,16) 线程 a 挂起线程 b 开始执行。
第一次循环
[1] (1,null)
第二次循环
[1] (35,1)->(1,null)
第三次循环
[1] (35,1)->(1,null)
[17] (16,null)
切换回线程 a,此时局部变量 e 和 next 被恢复,引用没变但内容变了:e 的内容被改为 (1,null),而 next 的内容被改为 (35,1) 并链向 (1,null)
第一次循环
[1] (1,null)
第二次循环,注意这时 e 是 (35,1) 并链向 (1,null) 所以 next 又是 (1,null)
[1] (35,1)->(1,null)
第三次循环,e 是 (1,null),而 next 是 null,但 e 被放入链表头,这样 e.next 变成了35(2 处)
[1] (1,35)->(35,1)->(1,35)
已经是死链了
jdk8以后采用尾插法,即转以后新table中链表上元素的顺序和旧列表相同,这样就不会出现并发死链的情况,但是多个线程情况下仍然会出现数据覆盖的情况。所以我们要想保证线程安全,在使用HashMap时就要加锁或者采用线程安全的容器,比如ConcurrentHashMap、Hashtable或者使用Collections.synchronizedMap(Map)创建线程安全的map集合。
查看原帖
点赞 评论
相关推荐
在发呆的大白菜很爱吃肉:我觉得还是别分析它这个系统了,看不懂
点赞 评论 收藏
分享
牛客热帖
正在热议
# 银行笔面经互助 #
2513次浏览 48人参与
# 运营商笔面经互助 #
2857次浏览 66人参与
# 快手校招 #
55240次浏览 1282人参与
# 国央企求职进展汇总 #
12669次浏览 62人参与
# 汇川技术求职进展汇总 #
46967次浏览 417人参与
# 比亚迪求职进展汇总 #
354383次浏览 1990人参与
# 三七互娱校招 #
33336次浏览 804人参与
# 毕业季,你想好怎么跟生活对线了吗? #
111217次浏览 2555人参与
# 硬件人的简历怎么写 #
186639次浏览 2459人参与
# 滴滴求职进展汇总 #
11930次浏览 147人参与
# 机械人值得去的车企 #
8299次浏览 32人参与
# 大厂还是考编 #
62973次浏览 1219人参与
# 通信硬件投递记录 #
279969次浏览 6410人参与
# 浅聊一下我实习的辛苦费 #
159961次浏览 1452人参与
# 想实习转正,又想准备秋招,我该怎么办 #
389380次浏览 4131人参与
# 选完offer后,你后悔学机械吗? #
7029次浏览 44人参与
# 无实习如何秋招上岸 #
559409次浏览 7076人参与
# 2023毕业生求职有问必答 #
99890次浏览 1221人参与
# OPPO求职进展汇总 #
460197次浏览 4096人参与
# 通信/硬件的薪资开多少,才值得去? #
31977次浏览 288人参与
# 谈薪时HR压价该怎么应对 #
84355次浏览 1006人参与
# 不给转正的实习,你还去吗 #
1267134次浏览 14045人参与