面试官:HashMap 为什么线程不安全?

a3f00205ab2e9177a6d9f2da7d55ec11.png

若有收获,请记得分享和转发哦

  • 1.jdk1.7中的HashMap

    • 1.1 扩容造成死循环分析过程

    • 1.2 扩容造成数据丢失分析过程

  • 2.jdk1.8中HashMap

  • 总结


前言:我们都知道HashMap是线程不安全的,在多线程环境中不建议使用,但是其线程不安全主要体现在什么地方呢,本文将对该问题进行解密。

1.jdk1.7中的HashMap

在jdk1.8中对HashMap做了很多优化,这里先分析在jdk1.7中的问题,相信大家都知道在jdk1.7多线程环境下HashMap容易出现死循环,这里我们先用代码来模拟出现死循环的情况:

ff9dab4548c9ae60112b5a1c7917c958.png

53e8c3af0da8ae4bea7e9bfeba779ee0.png

0014680d9fc83d404a2a82631bd571ee.png

6b7be2626f791cf6878d5b9aa1c20d22.png

54c397be395f14e6afcbfed7d1dd6390.png

780379daeede16257660e4d5473901b3.png

1376c79859d07ce28bd195d13394fa3d.png

23515a65f856bf5fc521cccbe5741260.png

4132c4300f1d7aba5632eda7fccd2c68.png

newTable[3]=e ----> newTable[3]=3
e=next ----> e=7

此时结果如下:

ebda72602a945d2cb85b7d6b56dc18b9.png

继续循环:

e=7
next=e.next ----> next=3【从主存中取值】
e.next=newTable[3] ----> e.next=3【从主存中取值】
newTable[3]=e ----> newTable[3]=7
e=next ----> e=3

结果如下:

fff9e8e67cb5de246c2c5df3c3947d95.png

再次进行循环:

5677294c79c119a8afc58aa99ee92ac5.png

3d075954f41c0c648fa130f28293eadb.png

在后续操作中只要涉及轮询hashmap的数据结构,就会在这里发生死循环,造成悲剧。

1.2 扩容造成数据丢失分析过程

遵照上述分析过程,初始时:

f691c3bcdb2a41e66b285288c2ffb43c.png

线程A和线程B进行put操作,同样线程A挂起:

60409325bee49bad1344480d63ac9ba4.png

此时线程A的运行结果如下:

85fa1884d057d992d0291549fc9ade47.png

此时线程B已获得CPU时间片,并完成resize操作:

805ac7e7d2b72ea95f79a85b2464940d.png

同样注意由于线程B执行完成,newTable和table都为最新值:5.next=null

此时切换到线程A,在线程A挂起时:e=7,next=5,newTable[3]=null。

执行newtable[i]=e,就将**7放在了table[3]**的位置,此时next=5。接着进行下一次循环:

e9ce67a9ae2c74060761acb7a2d83fe6.png

9ffb62bc974e6dc20a21ed623bc6c3a7.png

37f7f3cff812a8f26050f43ee597796b.png

daa23cec0a8822d021a3e6d65f2423d0.png

98eb47b00ca7c92b327ee8b338efb7b3.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值