HashMap 为什么线程不安全

  Hashmap 在多线程下不安全,但是 在 jdk 1.7 和 jdk 1.8 不安全体现不同。

  在jdk1.7中,在多线程环境下,扩容时会造成环形链或数据丢失。

  在jdk1.8中,在多线程环境下,会发生数据覆盖的情况。

 

JDK1.7

  HashMap 1.7 多线程下不安全,体现在其扩容的时候。

  当两个线程同时 使用 put() 的时候,触发了扩容操作,扩容后,对应的节点的桶会产生环形链表,并在后续对该节点的轮询操作产生死循环。

  即下面的代码中产生。

void transfer(Entry[] newTable, boolean rehash) {
        int newCapacity = newTable.length;
        for (Entry<K,V> e : table) {
            while(null != e) {
                Entry<K,V> next = e.next;
                if (rehash) {
                    e.hash = null == e.key ? 0 : hash(e.key);
                }
                int i = indexFor(e.hash, newCapacity);
                e.next = newTable[i];
                newTable[i] = e;
                e = next;
            }
        }
}

 

 

JDK1.8

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

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

posted @ 2020-10-31 16:38  抽象Java  阅读(135)  评论(0编辑  收藏  举报