美文网首页个人学习
为什么HashMap不是线程安全的

为什么HashMap不是线程安全的

作者: Djbfifjd | 来源:发表于2020-09-01 09:41 被阅读0次

以JDK1.8的 HashMap 为例

HashMap 的 put 方法

其中造成线程不安全的方法主要是 resize() 扩容方法。

1️⃣情况一:
线程 A 和线程 B 共同对 HashMap 进行 put 操作。假设 A 和 B 插入的 Key-Value 中 key 的 hashcode 是相同的,这说明该键值对将会插入到 Table 的同一个下标的位置,会发生哈希碰撞,此时 HashMap 按照平时的做法是形成一个链表(若超过八个节点则是红黑树)。现在插入的下标为 null(Table[i]==null) 则进行正常的插入,此时线程 A 进行到了这一步正准备插入,这时候线程 A 堵塞,线程 B 获得运行时间,进行同样操作,也是 Table[i]==null,此时它直接运行完整个 put 方法,成功将元素插入。随后线程 A 获得运行时间接着上面的判断继续运行,进行了 Table[i]==null 的插入(此时实际是 Table[i]!=null 的操作,因为前面线程 B 已经插入了一个元素了),这样就会直接把原来线程 B 插入的数据直接覆盖了,如此非线程安全。在 hashmap 做 put 操作的时候会调用到以下的方法:

void addEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        if (size++ >= threshold)
            resize(2 * table.length);
}

A 线程和 B 线程同时对同一个数组位置调用 addEntry,两个线程会同时得到现在的头结点,然后 A 写入新的头结点之后,B 也写入新的头结点,那 B 的写入操作就会覆盖 A 的写入操作造成 A 的写入操作丢失。

2️⃣情况二:

这种情况是 resize 的时候造成的。假设 HashMap 中的 Table 情况如下: 线程 A 和线程 B 要对同一个 HashMap 进行 put 操作。插入后 Table 变为: 此时线程 A 和 B 都需要对 HashMap 进行扩容。假设线程 A 没有堵塞过,顺利完成 resize 后 Table 如下(这里的元素位置都是假设的): 如果线程 B 的 resize 是在 Entry3 的时候堵塞的,那么当它再次执行的时候就会造成如下图处形成一个循环链表,当进行 get 操作时候可能陷入死循环。

原因是:
线程 B 获得 CPU 时 e = Entry3,next = Entry2; 正常赋值,然后进行下一次循环遍历时要注意,此时 HashMap 已经是被线程 A resize 过的了,那么就有 e = Entry2,next = Entry3;头插法插入此时:

接着循环,e = Entry3,next = Entry3.next = null(看图),此时再头插就会形成循环链表了。

循环 头插法代码: 头插法

当多个线程同时检测到总数量超过门限值的时候就会同时调用 resize 操作,各自生成新的数组并 rehash 后赋给该 map 底层的数组 table,结果最终只有最后一个线程生成的新数组被赋给table变量,其他线程的均会丢失。而且当某些线程已经完成赋值而其他线程刚开始的时候,就会用已经被赋值的 table 作为原始数组,这样也会有问题。

相关文章

  • HashMap相关

    HashMap是数组+链表 1.HashMap不是线程安全,为什么不是线程安全的呢? 多线程put,多线程reha...

  • 专题一 Hashtable、ConcurrentHashMap

    线程安全的HashMap,ConcurrentHashMap HashMap是线程安全的吗?: 不是。多线程环境下...

  • HashMap问答

    HashMap是不是线程安全? 不是线程安全的。 为什么不安全? 线程不安全的两个添加是,数据可共享、可修改。Ha...

  • HashMap / HashTable / Concurrent

    HashMap与HashTable: HashMap不是线程安全的,HashTabe是线程安全的,并发环境中使用H...

  • HashMap和HashTable

    1.HashMap不是线程安全的,HashTable是线程安全的一个Collection。 2.HashMap允许...

  • ConcurrentHashMap源码分析

    1. 为什么需要ConcurrentHashMap HashMap不是线程安全的,多线程环境下使用会导致CPU占用...

  • 记录面试map

    1.hashmap数据结构?是线程安全吗?为什么不是线程安全?1.8为什么用黑红树?1.8为什么大于8使用红黑树?...

  • 2018-03-08 面试随笔——记录一些面试中碰到的问题(初级

    Q:为什么HashMap是非线程安全的?在什么情况下会发生非线程安全问题? A:HashMap是非同步的,一个线程...

  • 面试题收集

    一面HashMap 是线程安全的吗?Hashtable为什么是线程安全的? ConcurrentHashmap怎么...

  • 阿里

    HashMap、HashTable和ConcurrentHashMap HashMap不是线程安全的,Key和Va...

网友评论

    本文标题:为什么HashMap不是线程安全的

    本文链接:https://www.haomeiwen.com/subject/qdvmsktx.html