Java HashMap 扩容机制详解:触发条件与实现原理

原文来自于:zha-ge.cn/java/54

Java HashMap 扩容机制详解:触发条件与实现原理

有时候,写 Java 写着写着,HashMap 就开始耍小脾气。要么莫名其妙慢下来,要么空间蹭蹭见底,最后一看,原来是扩容背锅。今天就来聊聊我和 HashMap 扩容那些见不得人的内幕,顺便带一点代码小料。


那次 HashMap 把我搞懵了

先交代下场景:那会儿我在做个高并发日志聚合服务,业务量增长飞快。内存明明还挺大,CPU 占用突然就暴涨。下意识觉得啥锁卡死了?JDWP 监控半天,发现某段业务竟然全卡在 HashMap 里!我的第一反应:不会是扩容在搞事吧?

于是就打开源码,边啃边吐槽。


扩容的小九九

HashMap 的扩容,其实是"一拍脑门"规律。

  • 容量(capacity):桶的个数
  • 负载因子(loadFactor):默认 0.75
  • 扩容阈值(threshold):capacity × loadFactor

只要 size 超过 threshold,HashMap 就要大搬家!每次容量翻倍,然后 Rehash,老键全都要洗个三温暖。堪比程序员大重构。

小代码一把梭

来抄下源码核心片段,约 10 行出头:

java 复制代码
if (size >= threshold) {
    // 升级容量
    resize();
}

void resize() {
    // 容量变两倍
    Node<K,V>[] newTab = new Node[oldCap << 1];
    // 重哈希老数据
    for (Node<K,V> e : oldTab) {
        // ...把节点丢进新桶
    }
}

有没有发现?扩容一到位,CPU 很快就不淡定。插入不是"补一块砖",而是"全楼拆迁"。


踩坑瞬间

有些朋友老喜欢这么用:

java 复制代码
Map<String, String> map = new HashMap<>();
for (...) {
    map.put(k, v);  // 插满自动扩容!
}
  • 没指定初始容量,默认开 16 个桶。
  • 业务数据一多,每塞满 12 个元素就 realloc 一次。
  • 瞬间三连扩容 + Rehash,内存抖三抖。

最骚的是,如果你用大小刚好 2 的幂,感觉没问题。可有业务激增,过 thousand 条,扩容抖得比我写的周报还频繁!那 CPU 峰值,真让人头皮发麻。


手动避坑指南

后来我乖多了。新建 HashMap,直接:

java 复制代码
int expectSize = 5000;
int initCapacity = (int) (expectSize / 0.75f) + 1; // 6670
Map<String, String> map = new HashMap<>(initCapacity);

技巧 combo:

  • 预估最大元素,按 0.75 加一刀。
  • 不要等着扩容惩罚 CPU。
  • 生产居然稳住了,再也没见到爆表。

经验启示

  • HashMap 扩容很 "懒",等到阈值才挪窝,一挪就全家搬家超耗能。
  • 预估好初始容量,能省老鼻子资源。要伸手就伸大一点!
  • 涉及大批量、高并发插入,一定要提前分配,别让扩容成"定时炸弹"。
  • 插入超多数据时,HashMap 真心不快,考虑别的 Map 实现(比如 ConcurrentHashMap)。

哦对,这次学乖了。以后看到 HashMap,先估一把容量,不做小气鬼,代码和 CPU 都能松口气。反正内存又不是自己掏钱买的(老板:你说啥?)。 OK,今天 HashMap 的"扩容风波"就聊到这,溜了溜了------下次再踩坑记得拉我一把。

相关推荐
weixin_422329315 分钟前
AgentScope Java 项目入门 & Builder 深度解读
java·开发语言·人工智能
shepherd1268 分钟前
一次把 Spring MVC 文件上传参数“查没了”的排查:multipart、Filter 与 request body 的连环坑
java·后端·spring·mvc
宠友信息18 分钟前
Spring Boot与异步审核构建仿小红书源码内容发布全流程
java·数据库·spring boot·redis·mysql·oracle·uni-app
Listen·Rain25 分钟前
Springboot整合RedisStack
java·spring boot·redis
花和满楼35 分钟前
K8s 1.36 ImageVolume GA:OCI 镜像不再只能跑容器
java·容器·kubernetes
头茬韭菜39 分钟前
3.9 成本预警 — 退出钩子、$5 阈值对话框与多通道成本通知
java·大数据·jvm·ai
重庆小透明1 小时前
今日收获(一些个人思考)
java·spring·大模型·springai·prompt注入
Edward111111111 小时前
一AI名词
java·开发语言·数据库·学习
栈溢出了1 小时前
Redis repl_backlog 学习笔记
java·开发语言·redis·学习
并不喜欢吃鱼2 小时前
从零开始 C++----- 十五.一文吃透 C++ 异常:try-catch、栈展开、自定义异常、异常安全 noexcept 底层全剖析
java·开发语言·jvm