图解JDK7及其早期版本HashMap扩容死锁问题
在JDK7及其早期版本中HashMap在多线程环境下会发生扩容死锁的问题。
HashMap中在创建时默认会有16个桶,有一个默认加载因子0.75,如果Map中的Entry数量达到阈值(16*0.75)就会进行扩容,将原来的桶的数量扩展至原来的两倍,而在多线程环境下JDK7的HashMap会产生扩容死锁的问题。
下列方法是Map进行扩容的核心方法:
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable, initHashSeedAsNeeded(newCapacity));
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
/**
* 将所有Entry从当前表转移到新表。
*/
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> next = e.next;//1
//计算Hash,然后计算新数组中的索引值
/*if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);*/
e.next = newTable[i];//2
newTable[i] = e;//3
e = next;//4
}
}
}
我们大致可以将Entry的重散列看成四步:
- Entry<K,V> next = e.next;
- e.next = newTable[i];
- newTable[i] = e;
- e = next;
我们分别将上面四行代码编号为:1、2、3、4
现在我们来重现多线程情况下扩容死锁的情况,为了方便演示,我们将原始Map的桶的数量定为4,扩容后容量翻倍变为8,原Map中有两个Entry需要重散列,分别为:A、B。
- 线程二执行完代码行1,阻塞:

- 线程一开始执行,并执行完代码行1:

- 线程一执行代码行2,假设我们在扩容时两个节点新索引值为5:
e.next = newTable[5];
由于此时newTable[5]==null所以就相当于e.next=null,也就是A.next=null。

4. 线程一执行代码行3:

5. 线程一执行代码行4:

- 线程一再次进入循环执行代码行一,此时线程一中next变量指向null:

7. 线程一执行代码行2:

8. 线程一执行代码行3:

- 线程一执行代码行4:

此时线程一的扩容工作已经进行完毕,我们开始回到线程二。
线程二执行代码行2:
e.next = newTable[i];
由于线程二的newTable[i]=null,而e.next也就是A.next本来就为空,所以这句话在此时并未对结构造成实质影响。

- 线程二执行代码行3:

12. 线程二执行代码行4:

- 线程二再次循环执行代码行1:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iE9kg19T-1573800259936)(…/images/29.png)]
线程二执行代码行2:
本行代码对结构无影响

线程二执行代码行3:

线程二执行代码行4:

- 线程二执行代码行1:

18. 线程二执行代码行2(成环):

此时A、B两节点之间就会形成环形结构。
线程二执行代码行3:

线程二执行代码行4:

在JDK8中由于采取了不同的扩容机制,所以在JDK8中不会出现扩容死锁问题。但是这并不意味着JDK8的HashMap是线程安全的。
图解JDK7及其早期版本HashMap扩容死锁问题的更多相关文章
- JDK7与JDK8中HashMap的实现
JDK7中的HashMap HashMap底层维护一个数组,数组中的每一项都是一个Entry transient Entry<K,V>[] table; 我们向 HashMap 中所放置的 ...
- 关于JDK1.8 HashMap扩容部分源码分析
今天回顾hashmap源码的时候发现一个很有意思的地方,那就是jdk1.8在hashmap扩容上面的优化. 首先大家可能都知道,1.8比1.7多出了一个红黑树化的操作,当然在扩容的时候也要对红黑树进行 ...
- 将“早期版本的Windows”改名
将“早期版本的Windows”改名,并修改系统等待时间 问题描述: 先装Windows XP,再装Windows 7,启动菜单会出现“早期版本的Windows”与“Windows 7”两个 ...
- 安装了SQL2005再安装SQL 2008R2,提示此计算机上安装了 Microsoft Visual Studio 2008 的早期版本和检查是否安装了 SQL Server 2005 Express 工具的解决方案
工作电脑上安装了SQL 2005, 但是客户电脑上安装的是SQL 2008R2,有时候连接他们的库调试没法连接,很不方便.然后又安装了个SQL2008 R2,期间遇到这两个问题,网上搜索了一下收到了解 ...
- SQL SERVER安装提示“安装了 Microsoft Visual Studio 2008 的早期版本
工作共遇到的问题记录: 安装Sql Server 2008 R2时提示错误:“此计算机上安装了 Microsoft Visual Studio 2008 的早期版本.请在安装 SQL Server 2 ...
- 【转】预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)
用VC++ 2008 编写C语言程序,编译出现错误: 预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反) 解决方法: 建工程时 建立空项目 或者在项目设置里关闭预编 ...
- VS2005 MFC 预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)
当 Visual C++ 项目启用了预编译头 (Precompiled header) 功能时,如果项目中同时混合有 .c 和 .cpp 源文件,则可能收到 C1853 编译器错误:fatal err ...
- Java 垃圾回收机制(早期版本)
Java 垃圾回收机制在我们普通理解来看,应该视为一种低优先级的后台进程来实现的,其实早期版本的Java虚拟机并非以这种方式实现的. 先从一种很简单的垃圾回收方式开始. 引用计数 引用计数是一种简单但 ...
- [转帖]Windows 10 部分早期版本已完全停止技术支持服务
Windows 10 部分早期版本已完全停止技术支持服务 2019-4-12 01:27| 发布者: cjy__05| 查看: 10186| 评论: 47|来自: pcbeta 收藏分享 转帖来源:h ...
- 面试笔记--HashMap扩容机制
转载请注明出处 http://www.cnblogs.com/yanzige/p/8392142.html 扩容必须满足两个条件: 1. 存放新值的时候当前已有元素的个数必须大于等于阈值 2. 存放新 ...
随机推荐
- 使用GUI--tkinter 制作一个批量修改文件名的桌面软件
''' title:批量修改文件名称 author:huyang createtime:2021-01-29 14:50:00 ''' from tkinter import * from tkint ...
- 机器学习&深度学习 操作tips
1. 在运行程序时,报错如下: usage: run.py [-h] --model MODEL [--embedding EMBEDDING] [--word WORD] run.py: error ...
- 【鸿蒙千帆起】《钢岚》成为首款基于HarmonyOS NEXT开发的战棋新游
近日,紫龙游戏旗下BlackJack工作室全新战棋旗舰作品<钢岚>在华为游戏中心首发上线,并宣布<钢岚>完成鸿蒙原生应用开发,成为基于HarmonyOS NEXT开发的首款 ...
- NL2SQL进阶系列(1):DB-GPT-Hub、SQLcoder、Text2SQL开源应用实践详解
NL2SQL进阶系列(1):DB-GPT-Hub.SQLcoder.Text2SQL开源应用实践详解 NL2SQL基础系列(1):业界顶尖排行榜.权威测评数据集及LLM大模型(Spider vs BI ...
- SRC信息收集方法论
"感谢您阅读本篇博客!如果您觉得本文对您有所帮助或启发,请不吝点赞和分享给更多的朋友.您的支持是我持续创作的动力,也欢迎留言交流,让我们一起探讨技术,共同成长!谢谢!" SRC信息 ...
- HL7传输协议
HL7消息通过各种TCP/IP传输发送,其中一些包括: 下层协议(LLP) 文件传输协议(FTP) 简单对象访问协议(SOAP) 简单邮件传输协议(SMTP) 尽管HL7可以使用多种传输协议进行数据传 ...
- 力扣275(jav&python)-H 指数 II(中等)
题目: 给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数,citations 已经按照 升序排列 .计算并返回该研究者的 h 指数. h ...
- OpenKruise v1.1:功能增强与上游对齐,大规模场景性能优化
简介:在 v1.1 版本中,OpenKruise 对不少已有功能做了扩展与增强,并且优化了在大规模集群中的运行性能.以下对 v1.1 的部分功能做简要介绍. 作者:酒祝(王思宇) 云原生应用自动化管理 ...
- 阿里的 RocketMQ 如何让双十一峰值之下 0 故障?
简介: 2020 年双十一交易峰值达到 58.3 W 笔/秒,消息中间件 RocketMQ 继续数年 0 故障丝般顺滑地完美支持了整个集团大促的各类业务平稳. 作者 | 愈安来源 | 阿里巴巴云原生公 ...
- HBase读链路分析
简介:HBase的存储引擎是基于LSM-Like树实现的,更新操作不会直接去更新数据,而是使用各种type字段(put,delete)来标记一个新的多版本数据,采用定期compaction的形式来归 ...