其他分享
首页 > 其他分享> > HashMap线程不安全分析

HashMap线程不安全分析

作者:互联网

HashMap线程安全问题

在分析HashMap线程安全问题之前,我们先看看什么是线程安全,线程安全问题是怎么引起的

一、什么是线程安全

线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。


百度百科

当多个线程同时对同一资源(变量)进行操作时,可能出现数据结果和我们预期结果不一致的情况,这种情况就是线程不安全的表现

线程安全问题大多是由共享资源引起的,共享资源一般是全局变量或局部变量

有了上面的知识我们再来分析HashMap的线程安全问题

二、HashMap的线程安全问题

我们先来看一下HashMap的存值流程

哈希表元素存储流程


图片来源于网络

1、数据覆盖

2、get值为null

Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;

这时resize方法中的两行代码,当一个线程执行完这两行之后挂起,这时map的数组为空,这时get元素为null

3、死循环(JDK7以前)

以下是jdk7中HashMap扩容的核心代码

//数据迁移的方法,头插法添加元素
void transfer(Entry[] newTable, boolean rehash) {
    int newCapacity = newTable.length;
    //for循环中的代码,逐个遍历链表,重新计算索引位置,将老数组数据复制到新数组中去(数组不存储实际数据,所以仅仅是拷贝引用      //而已)
    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);
            //将当前entry的next链指向新的索引位置,newTable[i]有可能为空,有可能也是个entry链,如果是entry链,直接在链               //表头部插入。
            //以下三行是线程不安全的关键
            e.next = newTable[i];
            newTable[i] = e;
            e = next;
        }
    }
}

正常的扩容流程是依次计算出每个元素在新数组中的hash值,然后使用头插法存到相应的位置,流程如图

 

多线程下造成死循环的流程如下

 

标签:HashMap,newTable,next,安全,线程,数组
来源: https://blog.csdn.net/qq_43572520/article/details/121082786