Java HashMap线程不安全,根本原因是其设计不承担并发保护职责:扩容时头插法易成环致死循环(JDK7)、put非原子性导致数据覆盖、size等关键字段未用volatile修饰引发可见性问题、迭代器fail-fast机制仅报错不保障并发安全。

Java 中 HashMap 是非线程安全的,根本原因在于它从设计之初就**不承担并发保护职责**——所有关键操作都未加同步机制,且内部状态变更缺乏可见性与原子性保障。多线程同时读写时,极易引发数据错乱、结构破坏甚至程序卡死。
扩容时链表成环导致死循环
JDK 7 中,扩容采用头插法迁移链表节点。当两个线程同时触发 resize,可能因竞态条件使节点 A 和 B 的 next 指针互相指向,形成环形链表。后续 get() 遍历时陷入无限循环,CPU 占用飙升至 100%。JDK 8 虽改用尾插法避免成环,但扩容过程仍非原子,仍可能丢失数据或读到中间态。
put 操作不是原子动作
一次 put 包含多个步骤:计算 hash → 定位桶位置 → 检查 key 是否存在 → 插入或覆盖 value。这些步骤未被锁或 CAS 保护,线程 A 执行到一半时被中断,线程 B 同样操作同一桶,可能导致:
- A 判断 key 不存在后准备插入,B 已插入成功,A 覆盖 B 的值
- A 和 B 同时插入新节点,其中一个 silently 丢失
- size 字段未用 volatile 修饰,A 修改后 B 仍读到旧值,误判容量未满而不扩容
关键字段无内存可见性保证
table 数组、size、threshold 等核心字段均未声明为 volatile。一个线程对 table 的扩容完成并更新 size,另一个线程可能因 CPU 缓存未刷新,继续使用过期的 table 引用和 size 值,造成索引越界、空指针或重复扩容等异常行为。
立即学习“Java免费学习笔记(深入)”;
迭代器不支持并发修改
HashMap 的 Iterator 是 fail-fast 的。若遍历过程中有其他线程调用 put 或 remove,modCount 与 expectedModCount 不一致,立刻抛出 ConcurrentModificationException。这不是设计缺陷,而是明确警示:它不承诺在迭代期间容忍结构变更。


















