图解JDK1.7中HashMap头插法扩容造成的死循环问题

扩容源码

先来看一下扩容的源码

void resize(int newCapacity) {
  Entry[] oldTable = table;
  int oldCapacity = oldTable.length;
  if (oldCapacity == MAXIMUM_CAPACITY) {
    threshold = Integer.MAX_VALUE;
    return;
  }

  //根据新的长度创建好的newTable
  Entry[] newTable = new Entry[newCapacity];
  
  // initHashSeedAsNeeded(newCapacity)这个返回值为false
  // 转移
  transfer(newTable, initHashSeedAsNeeded(newCapacity));
  table = newTable;
  // 计算容量*负载因子
  threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}

// newTable表示新创建的扩容后的数组
// rehash表示元素是否需要重新计算哈希值
void transfer(Entry[] newTable, boolean rehash) {
    
    // 记录新数组的容量
    int newCapacity = newTable.length;
    
    // 遍历原数组的桶位置
    for (Entry<K,V> e : table) {
        
        // 如果桶位置不为空,则遍历链表的元素
        while(null != e) {
            
            // next表示原数组链表的下一个节点
            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;
        }
    }
}

举例说明

假设有两个线程同时扩容,都需要数据迁移,线程A和B都执行到了Entry<K,V> next = e.next;这一行

Alt

这时线程B的时间分片执行完了,而A继续执行并执行完整个扩容,此时的 table 如下图:
Alt

线程B分到了时间分片,继续执行

第一轮循环

e = C, next = B

e.next = newTable[i]; // newTable[i]是null,所以C的next是null

newTable[i] = e; // newTable[i]是C

e = next; // B

在这里插入图片描述

第二轮循环

e = B

Entry<K,V> next = e.next; // 从线程A扩容完得到的新的table可知,B的next是C

// 。。。

e.next = newTable[i]; // newTable[i]是C,所以B的next是C

newTable[i] = e; // newTable[i]是B

e = next; // C

在这里插入图片描述

第三轮循环

e = C

Entry<K,V> next = e.next; // 从线程A扩容完得到的新的table可知,C的next是null

// 。。。

e.next = newTable[i]; // newTable[i]是B,所以C的next是B

newTable[i] = e; // newTable[i]是C

e = next; // null

在这里插入图片描述

如图所示,已经形成了死循环

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值