• JDK1.7和JDK1.8中HashMap为什么是线程不安全的?


    https://blog.csdn.net/swpu_ocean/article/details/88917958

    HashMap的线程不安全体现在会造成死循环、数据丢失、数据覆盖这些问题。其中死循环和数据丢失是在JDK1.7中出现的问题,在JDK1.8中已经得到解决,然而1.8中仍会有数据覆盖这样的问题。

    扩容引发的线程不安全

    void resize(int newCapacity) {
            Entry[] oldTable = table;
            int oldCapacity = oldTable.length;
            // 如果之前的HashMap已经扩充打最大了,那么就将临界值threshold设置为最大的int值
            if (oldCapacity == MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return;
            }
    
            // 根据新传入的newCapacity创建新Entry数组
            Entry[] newTable = new Entry[newCapacity];
            // 用来将原先table的元素全部移到newTable里面,重新计算hash,然后再重新根据hash分配位置
            transfer(newTable, initHashSeedAsNeeded(newCapacity));
            // 再将newTable赋值给table
            table = newTable;
            // 重新计算临界值,扩容公式在这儿(newCapacity * loadFactor)
            threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
        }

    HashMap的线程不安全主要是发生在扩容函数中,即根源是在transfer函数中,JDK1.7中HashMaptransfer函数如下:

     1 void transfer(Entry[] newTable, boolean rehash) {
     2         int newCapacity = newTable.length;
     3         for (Entry<K,V> e : table) {
     4             while(null != e) {
     5                 Entry<K,V> next = e.next;
     6                 if (rehash) {
     7                     e.hash = null == e.key ? 0 : hash(e.key);
     8                 }
     9                 int i = indexFor(e.hash, newCapacity);
    10                 e.next = newTable[i];
    11                 newTable[i] = e;
    12                 e = next;
    13             }
    14         }
    15     }

    这段代码是HashMap的扩容操作,重新定位每个桶的下标,并采用头插法将元素迁移到新数组中。头插法会将链表的顺序翻转,这也是形成死循环的关键点。理解了头插法后再继续往下看是如何造成死循环以及数据丢失的。

    扩容造成死循环和数据丢失的分析过程
    假设现在有两个线程A、B同时对下面这个HashMap进行扩容操作:

  • 相关阅读:
    oracle中查询或插入特殊字符
    html最多显示两行,css 实现两行或多行文本溢出显示省略号(...)
    RT
    发表一个自己做的WPF游戏
    用silverlight制作自己的GIS
    一个字符串切割问题
    Oracle所有者权限与调用者权限(转)
    Oracle角色权限的使用事项(转)
    Tomcat 内存溢出 详解
    forms验证:怎么验证两种身份?
  • 原文地址:https://www.cnblogs.com/dingpeng9055/p/11771445.html
Copyright © 2020-2023  润新知