Java 中的 HashMap 和 Hashtable 有什么区别?

一、线程安全性

特性 HashMap Hashtable
线程安全 非线程安全,需手动同步或使用 ConcurrentHashMap 所有方法使用 synchronized 修饰,线程安全
锁机制 无锁,多线程操作需外部同步 全表锁,并发性能较低
适用场景 单线程或需要高并发性能的场景 遗留代码维护,不推荐新项目使用

示例代码对比

// HashMap在多线程下需同步
Map<String, String> hashMap = new HashMap<>();
synchronized(hashMap) {
    hashMap.put("key", "value");
}

// Hashtable直接线程安全
Hashtable<String, String> hashtable = new Hashtable<>();
hashtable.put("key", "value"); // 自动同步

二、对 null 的支持

特性 HashMap Hashtable
键/值 允许 null 键和 null 不允许 null 键或值(抛出 NullPointerException
设计原因 灵活处理缺失值场景 早期设计限制,防止歧义

示例代码

// HashMap允许null
HashMap<String, String> map = new HashMap<>();
map.put(null, "value");       // 允许
map.put("key", null);         // 允许

// Hashtable禁止null
Hashtable<String, String> table = new Hashtable<>();
table.put(null, "value");     // 抛出NullPointerException

三、继承与实现

特性 HashMap Hashtable
父类 继承 AbstractMap 继承 Dictionary(已过时)
接口实现 实现 Map 接口 实现 Map 接口
迭代器 fail-fast 迭代器(快速失败) fail-fast 迭代器

类图对比

HashMap --> AbstractMap --> Map
Hashtable --> Dictionary --> Map

四、初始容量与扩容机制

特性 HashMap Hashtable
默认容量 16 11
扩容策略 容量翻倍(newCap = oldCap << 1 容量翻倍加一(newCap = (oldCap << 1) + 1
负载因子 默认 0.75 默认 0.75

扩容源码对比

// HashMap扩容逻辑(JDK17)
newCap = oldCap << 1;

// Hashtable扩容逻辑(JDK17)
int newCapacity = (oldCapacity << 1) + 1;

五、哈希冲突处理

特性 HashMap Hashtable
数据结构 数组 + 链表/红黑树(JDK8+) 数组 + 链表
树化阈值 链表长度≥8 且数组长度≥64 时转为红黑树 无树化机制
哈希计算 二次扰动(hashCode ^ (hashCode >>> 16) 直接使用 key.hashCode()

哈希扰动函数示例

// HashMap的哈希扰动(减少碰撞)
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

六、性能对比

场景 HashMap Hashtable
单线程操作 性能高(无锁开销) 性能较低(同步开销)
高并发读 需外部同步 性能差(全表锁阻塞)
高并发写 推荐使用 ConcurrentHashMap 性能极差

测试数据(10 万次操作,4 线程):

操作 HashMap Hashtable ConcurrentHashMap
纯写入 120ms 450ms 150ms
读写混合 180ms 600ms 200ms

七、使用建议

  1. 单线程场景

    • 优先选择 HashMap,性能更高。
  2. 高并发场景

    • 使用 ConcurrentHashMap 替代 Hashtable,分段锁机制更高效。
  3. 遗留系统维护

    • 若必须使用 Hashtable,需注意其性能瓶颈和 null 值限制。

总结

  • 线程安全Hashtable 通过全表锁实现线程安全,HashMap 非线程安全。
  • null 处理HashMap 允许 null 键值,Hashtable 禁止。
  • 性能HashMap 在单线程下性能更优,Hashtable 因同步开销性能较差。
  • 数据结构HashMap 采用更先进的红黑树优化冲突,Hashtable 仅使用链表。
  • 扩容机制:两者扩容策略不同,HashMap 扩容更高效。

在实际开发中,除非维护遗留代码,否则应优先选择 HashMapConcurrentHashMap,以获得更好的性能和扩展性。

你可能感兴趣的:(java,哈希算法,开发语言)