你知道为什么HashMap是线程不安全的吗?

我们都知道HashMap是线程不安全的,在多线程环境中不建议使用,但是其线程不安全主要体现在什么地方呢?

jdk1.7中的HashMap

扩容造成死循环

根源在transfer函数

在对table进行扩容到newTable后,需要将原来数据转移到newTable中,在转移元素的过程中,使用的是头插法,也就是链表的顺序会翻转,这里有机会形成环形列表,是形成死循环的关键点。

扩容造成数据丢失

出现数据覆盖,造成数据丢失。

jdk1.8中HashMap

jdk1.8中对HashMap进行了优化,在发生hash碰撞,不再采用头插法方式,而是直接插入链表尾部,因此不会出现环形链表的情况,但是在多线程的情况下仍然不安全。

put操作出现数据覆盖

在put操作的主函数中,如果没有hash碰撞则会直接插入元素。如果线程A和线程B同时进行put操作,刚好这两条不同的数据hash值一样,并且该位置数据为null,所以这线程A、B都会进入代码中。

假设一种情况,线程A进入后还未进行数据插入时挂起,而线程B正常执行,从而正常插入数据,然后线程A获取CPU时间片,此时线程A不用再进行hash判断了,问题出现:线程A会把线程B插入的数据给覆盖,发生线程不安全。

总结

首先HashMap是线程不安全的,其主要体现:

  • 在jdk1.7中,在多线程环境下,扩容时会造成环形链或数据丢失
  • 在jdk1.8中,在多线程环境下,会发生数据覆盖的情况

 

参考:

 

posted @ 2021-11-28 12:47  残城碎梦  阅读(146)  评论(0编辑  收藏  举报