若有收获,请记得分享和转发哦
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容易出现死循环,这里我们先用代码来模拟出现死循环的情况:
newTable[3]=e ----> newTable[3]=3
e=next ----> e=7
此时结果如下:
![ebda72602a945d2cb85b7d6b56dc18b9.png](https://i-blog.csdnimg.cn/blog_migrate/2237407f01a508f7a1f65480ef2130b5.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](https://i-blog.csdnimg.cn/blog_migrate/245583349a41592b0f23530cedef4d79.png)
再次进行循环:
在后续操作中只要涉及轮询hashmap的数据结构,就会在这里发生死循环,造成悲剧。
1.2 扩容造成数据丢失分析过程
遵照上述分析过程,初始时:
![f691c3bcdb2a41e66b285288c2ffb43c.png](https://i-blog.csdnimg.cn/blog_migrate/ce5e58e7398a3b9041a5f10a1161a5f0.png)
线程A和线程B进行put操作,同样线程A挂起:
![60409325bee49bad1344480d63ac9ba4.png](https://i-blog.csdnimg.cn/blog_migrate/1d06daa79d97399f81c3f8c1480bbd6e.png)
此时线程A的运行结果如下:
![85fa1884d057d992d0291549fc9ade47.png](https://i-blog.csdnimg.cn/blog_migrate/dba2edff67fe9739fda670ca37dca0ae.png)
此时线程B已获得CPU时间片,并完成resize操作:
![805ac7e7d2b72ea95f79a85b2464940d.png](https://i-blog.csdnimg.cn/blog_migrate/c5f78184cf0cebb702b7f16d93837084.png)
同样注意由于线程B执行完成,newTable和table都为最新值:5.next=null。
此时切换到线程A,在线程A挂起时:e=7,next=5,newTable[3]=null。
执行newtable[i]=e,就将**7放在了table[3]**的位置,此时next=5。接着进行下一次循环: