当红黑树节点数≤6时立即退化为链表,由remove、replace或clear等操作后主动触发;退化时重建Node链表而非复用TreeNode;采用6/8非对称阈值防止频繁切换。

当 HashMap 中某个桶的红黑树节点数量减少到 6 个或更少时,会自动退化为链表。这不是被动等待,而是每次执行删除(remove)、替换(replace)或批量清理操作后,在相关方法内部主动检查并触发的。
退化的触发时机
退化行为发生在对树节点进行修改之后,且仅针对当前发生变更的那个桶。关键点是:只要该桶中红黑树的节点总数 ≤ 6,就会立即开始退化流程,不依赖其他桶状态,也不看数组总容量。
- 调用
remove(key)删除一个键,导致树节点数从 7 变为 6 → 触发退化 - 调用
clear()清空整个 map,所有树桶都会逐个退化为链表(即使只剩 1 个节点) - 迭代过程中使用
Iterator.remove()删除元素,同样会检查并可能退化
退化过程不是简单“拆树”
退化不是把 TreeNode 直接连成链表,而是重建结构:
- 遍历当前红黑树的所有节点(通过
TreeNode的next指针,它保留了插入顺序) - 为每个节点创建新的
Node实例(非TreeNode),复用原 key、value、hash 值 - 按遍历顺序将这些
Node串成单向链表,头节点写回桶数组对应位置 - 原
TreeNode对象被丢弃,不再参与后续操作
为什么阈值设为 6 而不是 8
树化和退化使用不对称阈值(8 树化 / 6 退化),目的是防止在临界点附近频繁来回切换:
- 如果都用 8,那么增删交替时可能刚树化就退化、刚退化又树化,徒增开销
- 留出 2 个节点的缓冲区间,让结构变化更稳定,也符合“少量节点下链表更轻量”的设计权衡
- 6 是经过实测的平衡点:内存占用低、遍历快、构造成本几乎为零
退化后的影响
退化完成后,该桶完全回归链表逻辑:
-
get()查找重新变为 O(n) 线性比对(但 n ≤ 6,实际很快) - 后续
put()若再次发生冲突,仍走链表尾插;只有再次满足“长度 ≥ 8 且容量 ≥ 64”才会重新树化 - 该桶不再具备红黑树的
root、parent、颜色等字段,内存更紧凑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











