HashMap之环形链表源码图解

HashMap之环形链表源码图解

Java7在多线程操作HashMap时,并发扩容可能会导致环形链表,get方法时则可能出现死循环。以下是环形链表的具体产生过程。

1.扩容逻辑实现transfer()方法:

void transfer(Entry[] newTable, boolean rehash) {
    int newCapacity = newTable.length;
    for (Entry<K,V> e : table) {
          // 循环数组中元素,依次从copy到newTable
        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扩容到newTable的头位置,已有的newTable[i]会放到e的next。
               e.next = newTable[i];
            newTable[i] = e;
            e = next;
        }
    }
}

2.扩容前的HashMap数据:
在这里插入图片描述

3.线程一开始扩容,注意这句关键代码:

Entry<K,V> next = e.next;

假如线程一执行完这句代码时,就被挂起了,此时线程一transfer()方法中:e = entry1, next = entry0, entry0.next = null。

4.巧了,此时线程二也开始触发扩容:
当线程二扩容完成之后,假如扩容后entry0和entry1也落到newTable的同一index位置,此时线程二中的newTable数据为:
在这里插入图片描述

注意 重点来了,线程二扩容完成后之后,ertry0的next指向了entry1。

5.回到线程一继续扩容:
注意,此时线程一transfer()方法中:e = entry1, next = entry0, entry0.next = entry1。当第一个元素entry1扩容完成之后,此时线程一中的newTable数据为:
在这里插入图片描述

此时 e = entry0, next = entry1, entry1.next = null。

6.线程一继续将e = entry0扩容copy到newTable中:
当元素entry0扩容完成之后,此时线程一中的newTable数据为:
在这里插入图片描述

此时 e = entry1, next = null。

7.线程一继续将e = entry1扩容到newTable中:
当元素entry1扩容完成之后,此时线程一中的newTable数据为:
在这里插入图片描述

注意 当这一轮扩容完成后,会把entry1.next = entry0,线程一扩容完成,同时线程二扩完容的时候,已经将entry0.next = entry1了,形成环形链表

8.当调用get()方法的时候,代码逻辑:

final Entry<K,V> getEntry(Object key) {
    if (size == 0) {
        return null;
    }
    int hash = (key == null) ? 0 : hash(key);
     // 问题就在这里,当key进行hash运算之后,刚好落在环形链表这个位置,
     // 当key没有匹配,会向下一直循环e.next,然后就在环形链表中出不来了。
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
        e != null;
        e = e.next) {
        Object k;
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k))))
            return e;
    }
    return null;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值