jdk1.7hashMap环链的产生以及jdk1.8对hashMap扩容的优化。

jdk1.7hashMap扩容

当我们插入值时,如果hashMap数组达到阈值且当前数组位置不为空,那么它就会进行扩容。但在jdk1.7版本中,多线程下,多个线程对一个hashMap操作是会产生环链的。
下面是hashMap扩容将元素转移的主要代码,也是环链产生的地方。

void transfer(Entry[] newTable) {
        Entry[] src = table;
        int newCapacity = newTable.length;
        for (int j = 0; j < src.length; j++) {
            Entry<K,V> e = src[j];
            if (e != null) {
                src[j] = null;
                do {
                    Entry<K,V> next = e.next;
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                } while (e != null);
            }
        }
    }

假如有两个线程P1、P2,以及table[]某个节点链表为 a->b->null(a、b是HashMap的Entry节点,保存着Key-Value键值对的值)
P1先执行,执行完"Entry<K,V> next = e.next;"代码后,P1发生阻塞或者其他情况不再执行下去,此时e=a,next=b。(自己画的图,比较丑,见谅)
在这里插入图片描述

P1阻塞后P2获得CPU资源开始执行,由于P1并没有执行完transfer(),table 和 threshold仍为原来的值,P2依旧会进行resize操作,并且P2顺利执行完resize()方法,假设a、b节点仍然rehash到newTable[](注意,P1和P2中newTable[]不是同一个)中同一个节点链表中,则新的节点链表为 b->a->null。此时线程一的e和next仍然指着a 和 b

在这里插入图片描述

P1又继续执行"Entry<K,V> next = e.next;"之后的代码,则newTable[i]的节点链表变化过程为:
第一次while循环,newTable[i]=a,链表为:b->a->null;此时e=b;
在这里插入图片描述

进入第二次循环,newTable[i]=b,数据全部转移到p1表

在这里插入图片描述

第三次循环则产生了环链B.next=A; A.next=B

在这里插入图片描述

jdk1.8hashMap扩容优化

jdk1.8在扩容时引入了高低位指针的概念。

在这里插入图片描述

将节点的hash直接与数组长度进行与运算,结果只为0和不为0两种结果。
这里为了方便理解我们假设数组长度为16。之前通过hash & (n- 1)获得hash值的第四位从而确定数组位置,但第五位我们并不知道,所以通过e.hash & oldCap计算出当前位置链表中所有节点的第五位是否为1。将所有第五位为0的节点放入lo链表,反之则放入hi链表。

000 0 0101——————》0留在原地 lo链表

000 1 0101——————》1移向高位 hi链表

001 0 0101——————》0留在原地 lo链表

001 1 0101——————》1移向高位 hi链表
在移动链表时,lo链表仍然放入新数组的当前位置,而hi链表则放入(久数组位置+久数组数组长度)的位置,这恰好对应扩容后位置计算表达式hash & (32- 1),前提是数组长度为2的整数次幂。

在这里插入图片描述

在这里插入图片描述

这样设计十分巧妙,直接带来了三个好处。

1、不需要重新再计算hash,性能得到提升;

2、放过去的链表内元素的相对顺序不会改变;

3、不会在并发扩容中产生环链的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值