news 2026/4/12 22:54:45

jdk1.7 在多线程下扩容可能导致的死循环问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
jdk1.7 在多线程下扩容可能导致的死循环问题

首先先看看 hashmap 在jdk1.7 下扩容的核心方法

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; // 断开旧数组的引用,虽然不是必须的,但有助于GC // 遍历链表,把链表上的节点一个一个摘下来,重新放到新数组里 do { // 【关键点1】先保存下一个节点,防止待会链表断了找不到后面的人 Entry<K,V> next = e.next; // 计算这个节点在新数组中的下标 int i = indexFor(e.hash, newCapacity); // 【关键点2】头插法核心:将当前节点 e 的 next 指向新数组位置原本的头节点 e.next = newTable[i]; // 【关键点3】将新数组该位置的头指针指向 e(e 变成了新的头节点) newTable[i] = e; // 【关键点4】继续处理旧链表的下一个节点 e = next; } while (e != null); } } }

可以看到,jdk1.7 版本下的扩容依靠的是头插法实现元素搬移

头插法 的特点:假设旧数组某个位置的链表是A -> B -> C。 因为代码逻辑是:每次把新来的元素插到最前面(e.next = newTable[i]然后newTable[i] = e)。 所以搬运到新数组后,顺序会倒置,变成C -> B -> A

为什么JDK 1.7用头插法? 设计者当时认为,后插入的数据被访问的概率更高(热点数据),放在头部查得快。但这在多线程下埋下了祸根。

那其实在多线程的情况下就会有问题了,举个例子:

假设有两个线程Thread 1Thread 2同时在扩容。 旧链表结构:A -> B。 线程 1 执行到你注释的那一行挂起了(Paused):

Entry<K,V> next = e.next; // 线程1在这里卡住了! // 此时对于线程1来说: e = A, next = B
接下来可能发生的事情:
  1. 线程 2 抢占 CPU 完成了扩容
    • Thread 2 把AB都搬到了新数组。
    • 注意:因为是头插法,顺序反了
    • 在新内存里,现在的链表结构是:B -> A(B 指向 A,A 指向 null)。
  1. 线程 1 醒来继续执行
    • Thread 1 里的变量还停留在挂起前的状态:e = Anext = B
    • Thread 1 开始干活:
      • 将 A 指向 B
      • 头节点变成 A
      • 此时 A 指向 B,B 指向 A(死循环开始)
  1. 线程 1 接着处理 B,B 头插当头节点,此时 B 指向 A,A 指向 B
  2. 然后接着处理 A,A 头插当头节点,此时 A 指向 B,B 指向 A
  3. 然后循环往复 A,B 轮流当头节点,死循环

如图:


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/12 6:16:06

Obsidian文档结构优化利器:智能标题自动编号完全指南

Obsidian文档结构优化利器&#xff1a;智能标题自动编号完全指南 【免费下载链接】number-headings-obsidian Automatically number headings in a document in Obsidian 项目地址: https://gitcode.com/gh_mirrors/nu/number-headings-obsidian 你是否曾在撰写长篇笔记…

作者头像 李华
网站建设 2026/4/9 0:26:38

超声造影成像工程技术要点

一、超声造影成像核心技术原理微泡动力学基础 造影剂采用直径为2–5μm的惰性气体微泡&#xff08;如六氟化硫&#xff09;&#xff0c;在声场作用下产生非线性振动响应关键参数&#xff1a;谐振频率范围为1–10MHz&#xff08;与微泡粒径呈反比关系&#xff09;&#xff0c;机…

作者头像 李华
网站建设 2026/4/8 14:20:18

Ubuntu 22.04 服务器上搭建 YOLOv8 环境并支持 Java 调用

第一步:系统准备和依赖安装 # 更新系统 sudo apt update && sudo apt upgrade -y# 安装基本工具 sudo apt install -y wget curl git build-essential python3-pip python3-venv 第二步:安装Python环境(推进使用conda) # 下载并安装 Miniconda wget https://rep…

作者头像 李华
网站建设 2026/4/1 2:36:58

HeidiSQL数据库管理工具:从零开始的高效数据操作指南

还在为复杂的数据库操作而烦恼吗&#xff1f;HeidiSQL作为一款免费的SQL编辑器和数据库管理工具&#xff0c;能够帮助数据库管理员和开发者轻松管理MySQL、PostgreSQL、SQLite等多种数据库。这款由Delphi编写的工具以其直观的图形界面和强大的功能特性&#xff0c;让数据库管理…

作者头像 李华
网站建设 2026/4/11 15:10:32

窗口置顶神器:彻底告别窗口遮挡烦恼的终极解决方案

窗口置顶神器&#xff1a;彻底告别窗口遮挡烦恼的终极解决方案 【免费下载链接】pinwin .NET clone of DeskPins software 项目地址: https://gitcode.com/gh_mirrors/pi/pinwin 在当今多任务并行的数字化工作环境中&#xff0c;窗口管理已成为影响工作效率的关键因素。…

作者头像 李华
网站建设 2026/4/10 22:31:23

兜兜英语单词:前缀cardio-心脏

&#x1fac0;cardio-心脏&#xff0c;这些单词直接“一串拿下”&#xff0c;附场景化例句超易记&#x1f447;1. Cardiology /ˌkɑːdiˈɒlədʒi/ 心脏病学 &#x1fa7a;&#x1f50d;构词&#xff1a;cardio- -logy&#xff08;学科&#xff09; &#x1f4ac;例句&…

作者头像 李华