Hashtable 自 JDK 1.2 起被弃用,应改用 ConcurrentHashMap;其全表锁导致并发性能差,不支持 null 键值,且哈希计算、扩容机制均落后于 HashMap。

别再用 Hashtable 了,它已经被淘汰
直接说结论:Hashtable 是 JDK 1.0 的遗留类,自 JDK 1.2 起就被标记为 @Deprecated(不推荐使用),官方文档明确建议用 HashMap + 同步机制,或更优的 ConcurrentHashMap 替代。你在新项目里写 new Hashtable(),CI/CD 流水线甚至可能报警告;IDE(如 IntelliJ)也会划波浪线提示“Use ConcurrentHashMap instead”。这不是风格偏好,而是事实性技术淘汰。
线程安全 ≠ 可用:为什么 Hashtable 的 synchronized 反而害人
Hashtable 所有方法(put()、get()、size() 等)都加了 synchronized,锁的是整个对象——也就是「全表锁」。这意味着:哪怕你只是并发读两个完全不相干的 key,也得排队等锁释放。
- 高并发下吞吐量骤降,QPS 可能只有
ConcurrentHashMap的 1/5~1/10 -
size()这种只读操作也要锁,而ConcurrentHashMap的size()是无锁估算,快得多 - 无法实现复合操作的原子性(比如「若不存在则 put」),
Hashtable仍需额外同步块
真要线程安全,请用:
Mapmap = new ConcurrentHashMap<>();
不是 Collections.synchronizedMap(new HashMap())——它也是全表锁,和 Hashtable 性能几乎一样差。
立即学习“Java免费学习笔记(深入)”;
null 键值支持:一个空指针异常就暴露选型错误
这是开发中最常踩的坑:Hashtable 对 null 零容忍,只要 put(null, "x") 或 put("k", null),立刻抛 NullPointerException;而 HashMap 允许一个 null 键(存于数组索引 0)、任意多个 null 值。
- Web 开发中常见场景:HTTP 参数未传时值为
null,用Hashtable直接崩 - 配置中心、缓存层常用
null表示「未设置」或「禁用」,Hashtable无法表达这类语义 - 调试时如果看到
NPE报在table.put(...),第一反应应是检查是否误用了Hashtable
底层差异不只是“老 vs 新”:哈希计算、扩容、树化全都不一样
这些细节直接影响性能和稳定性,尤其在数据量大、热点 key 多的场景:
-
HashMap容量强制为 2 的幂(默认 16),索引计算用位运算hash & (capacity - 1),比取模快一个数量级;Hashtable容量默认 11,索引用hash % capacity,还要先做hash & 0x7FFFFFFF保证正数 -
HashMap(JDK 8+)链表长度 ≥ 8 且数组容量 ≥ 64 时自动转红黑树,最坏查询从 O(n) 降到 O(log n);Hashtable始终只有链表,大量哈希冲突时性能断崖下跌 -
HashMap对hashCode()做扰动:(h = key.hashCode()) ^ (h >>> 16),减少低位碰撞;Hashtable直接用原始hashCode(),对低质量 hash 函数更敏感
如果你还在维护老系统里用 Hashtable 的代码,迁移成本其实很低:全局替换为 ConcurrentHashMap,删掉所有 contains()(它已废弃,改用 containsKey() 或 containsValue()),再检查是否有地方依赖 Enumeration ——那部分也该换成 Iterator 了。










