Skip to content

Hashtable:遗留的全同步哈希表

一句话警告

Hashtable 已被废弃。它是 JDK 1.0 的遗留代码,性能差、设计保守。现代 Java 代码永远不要用 Hashtable


Hashtable vs HashMap:有什么区别

Hashtable 和 HashMap 几乎一模一样,但有三个关键区别:

1. 线程安全的方式不同

java
// Hashtable:所有方法都 synchronized
public class Hashtable<K, V> {
    public synchronized V put(K key, V value) { ... }
    public synchronized V get(Object key) { ... }
    public synchronized V remove(Object key) { ... }
    // 等等...所有方法都加锁
}

// HashMap:方法不带 synchronized
public class HashMap<K, V> {
    public V put(K key, V value) { ... } // 没有 synchronized
    public V get(Object key) { ... }     // 没有 synchronized
}

2. null 的处理不同

java
Hashtable<String, Integer> ht = new Hashtable<>();
ht.put(null, 1);    // ❌ NullPointerException
ht.put("a", null);  // ❌ NullPointerException

HashMap<String, Integer> hm = new HashMap<>();
hm.put(null, 1);    // ✅ OK
hm.put("a", null);  // ✅ OK

3. 初始容量和扩容策略不同

特性HashtableHashMap
默认初始容量1116
扩容方式capacity * 2 + 1(奇数)capacity * 2(翻倍)
负载因子0.750.75

为什么 Hashtable 被废弃

问题 1:全局锁性能差

Hashtable 的所有操作共用一把锁。高并发下,所有线程排队等锁:

java
// 10 个线程同时读同一个 Hashtable
// 线程 1 在 get()
// 线程 2 在 put()
// 线程 3 想 get()
// → 线程 3 必须等线程 1 或线程 2 释放锁才能操作

性能对比:

10 线程并发写入 100 万元素:
  Hashtable: ~5000 ms  ← 全局锁,串行化
  ConcurrentHashMap: ~200 ms  ← 分段锁,并行化
  快了 25 倍

问题 2:迭代器是 fail-fast 的

Hashtable 的迭代器不支持并发修改,遍历过程中任何线程的修改都会抛出 ConcurrentModificationException

问题 3:API 设计保守

  • 不允许 null key 和 null value(很多场景不方便)
  • 很多现代 API(如 computeIfAbsent)都没有

如何迁移

从 Hashtable 迁移到 ConcurrentHashMap

java
// ❌ 旧代码
Hashtable<String, Integer> old = new Hashtable<>();
old.put("a", 1);
old.get("a");

// ✅ 新代码
ConcurrentHashMap<String, Integer> modern = new ConcurrentHashMap<>();
modern.put("a", 1);
modern.get("a");

// ✅ 如果不需要并发安全,直接用 HashMap
Map<String, Integer> simple = new HashMap<>();
simple.put("a", 1);
simple.get("a");

并发场景的选择

场景推荐
单线程HashMap
偶尔并发Collections.synchronizedMap(new HashMap<>())
高并发ConcurrentHashMap
高并发 + 需要排序ConcurrentSkipListMap

常见误解

误解 1:Hashtable 是线程安全的,所以更好

「线程安全」不等于「更好」。Hashtable 的全局锁在高并发下反而成为瓶颈。

误解 2:Hashtable 比 HashMap 更可靠

两者都是成熟的实现,都正确实现了 Map 接口。但 HashMap 有更好的性能和更现代的 API。

误解 3:遗留代码必须用 Hashtable

即使维护遗留代码,也应该逐步迁移到 ConcurrentHashMap


总结

特性HashtableHashMap
线程安全✅ 全局锁❌ 不安全
null 支持❌ 都不允许✅ key/value 都可 null
默认容量1116
扩容方式*2+1*2
推荐程度❌ 不推荐✅ 推荐

一句话:Hashtable 是 JDK 1.0 的产物,早该退出历史舞台了。


相关链接

基于 VitePress 构建