JDK源码-HashMap死锁分析

开篇明志

和前一片文章《JDK源码-HashMap》的写作目的差不多,在创作ConcurrentHashMap这片文章的时候,需要和HashMap做对比,《JDK源码-HashMap》着重介绍了内部实现原理,但是没有详细说明为什么HashMap为什么会发生死锁现象——导致它是非线程安全的。

一、HashMap底层实现

这块更详细的内容请移步《JDK源码-HashMap》

简单的可以从以下两个纬度去理解HashMap的底层实现原理。

  • 数组:充当索引
  • 链表:处理碰撞

HashMap用一个指针数组table,离散化key的作用,当加入一个 key 的时候,通过Hash算法,计算出 key所在的数组下标 i,如果table[i]位置的对象元素为null的时候,则直接将<key, value>加入即可;但是,如果table[i]位置已经被占用的话,则会发生冲突碰撞;此时,会在 table[i]上形成一个链表。

如果table太小,就会发生频繁碰撞;此时,查询时间复杂度由O(1)变为O(n).
因此,Hash 表的尺寸和容量非常重要。每次当有新的数据要插入Hash 表时,都会检查容量有没有超过 thredshold,如果超过,需要扩容 Hash 表,这需要改变重新计算hash分桶的位置—— rehash,这种操作是比较耗时的。

所以,在创建HashMap实例的时候需要预先估计一下需要处理的数据量的大小,提前将table的大小和装载因子load factor设置好,减少Hash碰撞的概率,同时也可以减少扩容hash表的次数,达到节约时间的目的。

二、源码阅读

根据前面的文章《JDK源码-HashMap》可以知道,当每次添加新元素都是在链表头部添加元素,那么,问题来了——为什么会造成死锁呢?按理说每次在链表头部添加元素的话,不可能出现死锁现象的。

问题就出在rehash过程,当将旧table元素转移到新的newTable的时候,我们一块来看看transfer()函数的源码,分析一下原因。

transfer()源码如下:

    /** * Transfers all entries from current table to newTable. */
    void transfer(Entry[] newTable, boolean rehash) {
        int newCapacity = newTable.length;
        //Step1 : 首先便利索引数组中的元素,Entry<K,V> e 存储了链表的入口元素
        for (Entry<K,V> e : table) {
            //Step2: 对链表上的每一个元素进行遍历,从Hash表的头部第一个元素开始
            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;
            }
        }
    }

总结:

  1. 首先便利索引数组中的元素,获取到链表的入口节点
  2. 对链表上的每一个节点遍历:先将 e.next 指向新 Hash 表的第一个元素(如果是第一次就是 null),这时候新 Hash 的第一个元素是 e,但是 Hash 指向的却是 e 没转移时候的第一个,所以需要将 Hash 表的第一个元素指向 e.
  3. while循环遍历链表节点,直到全部转移到新的newTable
  4. for循环遍历table,可以理解为链表的入口头节点,直到所有索引数组全部转移到新的newTable

可以看到转移过程是逆序的,转移前链表顺序是1->2->3,逆序转移后新的t顺序变成 3->2->1。现在就应该才得八九不离十了,是不是有可能在转移的过程中 出现1>2>3>1这种情况,形成一个头尾相连的链表。

    原文作者:zxca368
    原文地址: https://blog.csdn.net/xidiancoder/article/details/71056726
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞