JDK1.7的HashMap的环形链表

分析扩容的核心代码

java 复制代码
// 构建新数组
Entry[] newTable = new Entry[newCapacity];
// 迁移老数组数据到新数组
transfer(newTable, initHashSeedAsNeeded(newCapacity));
// 迁移完毕后,替换老数组
table = newTable;
java 复制代码
// 迁移数据的过程
void transfer(Entry[] newTable, boolean rehash){
    int newCapacity = newTable.length;
    // 外层遍历数组
    for (Entry<k,v> e:table){
        // 遍历链表
        // 2号线程走完第二次循环,完成迁移数据(如下图2所示)
        // 1号线程走完第二次循环,发现指向的是A(如下图3所示)
        // 1号线程走完第三次循环,完成迁移数据(如下图4所示)
        while(null != e){
            Entry<K,V> next = e.next;
            // 1号线程执行到这里停止
            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
图3
图4

JDK1.7中的HashMap是线程不安全的,可能会出现并发扩容的操作。

JDK1.7中的HashMap在迁移数据时,采用的是头插法,导致节点的next指针会有变化。

先迁移完的线程,可能会导致其他线程在扩容时,扩容到最后,将最开始的节点重新的插入到了头节点的位置,导致指针再次变化,从而形成了一个环形链表。

相关推荐
杨充4 分钟前
4.接口而非实现编程
java·后端·架构
不会就选b8 分钟前
算法日常・每日刷题--<快排>4
算法
梦梦代码精10 分钟前
基于ThinkPHP6 + Vue3的家政预约系统全解析:从LBS定位到自动派单的完整实现
java·docker·开源·php·代码规范
Keven_1114 分钟前
算法札记:树状数组的用途
数据结构·算法
wear工程师17 分钟前
@Transactional 标了却没开事务?先看这次调用有没有经过代理
java·spring
Joey_friends18 分钟前
指纹authenticate流程图
android·java·c++
用户6774371758121 分钟前
C++函数参数传递方式详解:string、string&、const string、const string&该怎么选?
算法
郑州光合科技余经理32 分钟前
家政O2O平台解析:从0搭建上门预约小程序解决方案
android·java·开发语言·前端·小程序·架构·php
cpp_25011 小时前
P1540 [NOIP 2010 提高组] 机器翻译
数据结构·c++·算法·队列·noip·洛谷题解
晚笙coding1 小时前
LeetCode 98:验证二叉搜索树 —— 从局部判断到全局范围约束的递归思想
算法·leetcode·职场和发展