JDK 8 将 HashMap 扩容链表迁移由头插法改为尾插法,核心是避免多线程扩容时因指针交错导致的链表成环与死循环;同时保障迭代顺序稳定、支持红黑树可靠树化,但不提供线程安全。

Java 中 HashMap 在 JDK 8 中将头插法改为尾插法,核心目的是解决多线程扩容时的链表成环问题,从而避免死循环;同时提升迭代顺序稳定性与红黑树转换的可靠性。
防止扩容时链表成环导致死循环
在 JDK 7 中,扩容(resize)采用头插法迁移链表节点。由于头插操作包含“设置 next 指针”和“更新头指针”两个非原子步骤,多线程并发执行时极易发生指令交错。例如:原链表为 A→B,两个线程同时迁移,可能使 A.next 指向 B、B.next 又指向 A,形成环形链表。后续 get 或遍历操作会陷入无限循环。
JDK 8 改用尾插法后,迁移过程中节点顺序保持不变(或按高低位拆分为两条有序链),各节点的 next 引用关系不被反转,从根本上切断了成环路径。
保障迭代顺序可预测
头插法天然导致后插入的元素排在链表头部,遍历时呈现逆序(如插入 A、B、C,遍历顺序为 C→B→A)。这不符合多数开发者对“插入先后”的直觉预期,尤其在调试、日志或临时缓存场景中容易引发困惑。
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
尾插法让新节点始终追加到末尾,链表顺序与插入顺序一致,迭代行为更稳定、可预期,也便于与 LinkedHashMap 的顺序语义保持逻辑统一。
适配红黑树转换机制
JDK 8 引入红黑树的前提是链表长度 ≥ 8 且数组容量 ≥ 64。该转换依赖节点间相对顺序的稳定性:树化过程需按插入顺序构建树结构,若链表本身因头插而频繁倒序,会增加树平衡调整的复杂度,甚至影响 key 比较逻辑的合理性。
尾插法维持原始插入次序,使树化过程更自然,节点分布更贴近实际使用模式,有利于红黑树保持良好平衡性。
不等于线程安全
需要明确的是:尾插法仅缓解了扩容阶段的成环风险,但 HashMap 整体仍不具备线程安全性。put、get 等方法无任何同步机制,多线程下仍可能出现数据覆盖、丢失、读取脏值等问题。真正需要并发安全,应选用 ConcurrentHashMap 或外加同步控制。

















