hashmap在jdk 8中当链表长度≥8且数组长度≥64时转为红黑树,以优化查找性能;退化条件是树节点数≤6,形成高低水位防震荡。

HashMap 在 JDK 8 中引入红黑树优化,是为了在哈希冲突严重时避免链表过长导致查找性能退化为 O(n)。是否转为红黑树,取决于两个关键条件,缺一不可。
链表长度 ≥ TREEIFY_THRESHOLD(默认为 8)
当某个桶(bucket)中的链表节点数达到或超过 8 时,触发树化判断。注意:这是“链表中实际存储的 Node 节点个数”,不包括头结点(HashMap 中链表无额外头结点,即从第一个 key-value 节点开始计数)。
- 插入新元素后,若该桶已有 7 个节点,再插入第 8 个 → 链表长度变为 8 → 满足长度条件
- 但仅满足长度还不够,还需检查 table 容量
哈希表数组长度 ≥ MIN_TREEIFY_CAPACITY(默认为 64)
即使链表长度达到 8,如果当前哈希表底层 table 数组长度小于 64,也不会树化,而是优先进行扩容(resize)。这是为了避免在小容量表中过早树化,增加不必要的结构复杂度和内存开销。
- 例如:初始容量为 16,某桶链表涨到 8 → 不树化,而是触发 resize,将容量扩为 32;若扩容后仍冲突集中,继续增长,直到 table.length ≥ 64 且链表长度 ≥ 8 才真正树化
- 这个设计体现了“用空间换时间”的权衡:扩容成本可控,而小表上维护红黑树反而得不偿失
树化过程不是简单“链表变红黑树”,而是重建结构
树化时,HashMap 会遍历原链表,将所有 Node 转为 TreeNode(红黑树节点),并根据 key 的 hash 值重新构建一棵左倾红黑树。TreeNode 同时保留 next 引用,兼容链表结构,便于后续可能的反树化(untreeify)。
- 树化过程中会校验 key 是否实现了 Comparable,若未实现且无法通过 equals 判断顺序,会抛出 ClassCastException
- 若 key 类型不支持比较(如自定义类未实现 Comparable 且未传入 Comparator),则无法完成树化,会退回到链表形式(但 JDK 8 实际会在 treeifyBin 中静默失败并保持链表,不会抛异常——除非调用方法时明确要求比较)
红黑树退化为链表的条件
与树化对应,当执行删除操作导致某红黑树节点数 ≤ UNTREEIFY_THRESHOLD(默认为 6)时,会将该树还原为普通链表。
- 注意:退化只发生在 resize 或 remove 过程中,且仅针对单个桶;不会因为全局负载降低而批量退化
- 退化阈值(6)比树化阈值(8)小,形成“高低水位”区间,避免频繁树化/退化震荡










