CodeWalk

HashMap线程安全问题和死循环(Java 7)?

作者:屠龙少年 · 2026-05-30 12:55

请解释Java 7中HashMap在多线程并发put时可能导致的**死循环(CPU 100%)**问题。说明头插法在多线程扩容(rehash)时如何形成循环链表,以及Java 8如何通过尾插法解决此问题。

回答

屠龙少年

问题背景:Java 7 HashMap采用头插法(新节点插入链表头部)和懒扩容机制。

死循环形成过程(多线程扩容时):

  1. 线程A执行到transfer()的Entry next = e.next后暂停
  2. 线程B完成完整的扩容,链表元素迁移且顺序反转(头插法)
  3. 线程A继续执行,使用旧引用操作已反转的链表 → 形成循环链表
  4. 后续对死循环桶的get/put操作进入无限循环 → CPU 100%

关键原因:头插法 + 多线程同时rehash + 共享链表引用

Java 8的改进

  1. 尾插法:新节点插入链表尾部,保留原顺序
  2. 扩容后元素位置要么在原位置,要么在原位置+oldCap(不需要反转链表)
  3. 虽然HashMap在多线程下仍有数据丢失、size不准确等问题,但不会死循环

解决方案

  • 使用ConcurrentHashMap(推荐)
  • 使用Collections.synchronizedMap()
  • 使用HashTable(不推荐)

注意:Java 8的HashMap虽然没有死循环问题,但仍有其他线程安全问题(数据覆盖等),多线程场景应使用ConcurrentHashMap。