ConcurrentHashMap 和 Hashtable 的区别详解

在 Java 集合框架中,Hashtable 和 ConcurrentHashMap 都是线程安全的 Map 实现,常被用来在多线程环境下存储键值对。很多初学者容易把它们混为一谈,认为功能一样就可以互换使用,但实际上两者在设计理念、性能、功能和适用场景上存在巨大差异。

主要区别

对比项 Hashtable ConcurrentHashMap (JDK 8) 说明与影响
出现版本 JDK 1.0(非常古老) JDK 1.5 引入,JDK 8 大幅重构 Hashtable 是遗留类,ConcurrentHashMap 是现代高并发首选
线程安全实现方式 所有公共方法都加 synchronized(对象级锁) 分段锁(JDK 7)→ CAS + synchronized(JDK 8) Hashtable 锁粒度大,并发度低;ConcurrentHashMap 锁粒度细,并发性能高
锁粒度 整个对象一把锁 JDK 8:单个桶(bucket)级别 synchronized + CAS ConcurrentHashMap 支持更高的并发读写
读操作是否加锁 是(get 也加 synchronized) 否(get 不加锁,基于 volatile 可见性) ConcurrentHashMap 的 get 操作无锁,读取性能极高
允许 null 键/值 不允许(put null 会抛 NullPointerException) 不允许键为 null,允许值为 null 两者都不允许 null 键,但 Hashtable 连值也不允许
迭代器行为 fail-fast(并发修改抛 ConcurrentModificationException) weak consistent(弱一致性),迭代器不会抛异常 ConcurrentHashMap 的迭代器能反映并发修改后的状态,更适合高并发遍历
容量扩容机制 容量为 2 倍 + 1,扩容时重新 hash 容量为 2 的幂次方,JDK 8 扩容时高效 rehash ConcurrentHashMap 扩容更高效,支持并发扩容
size()、isEmpty() 准确性 准确(加锁计算) 近似值(不加锁统计,可能有延迟) 高并发下 ConcurrentHashMap 的 size() 不保证实时精确,但性能更好
性能(高并发场景) 较低(全表锁) 极高(细粒度锁 + 无锁读) 实际生产环境中,ConcurrentHashMap 性能通常是 Hashtable 的数倍到数十倍
是否推荐继续使用 不推荐(已过时) 强烈推荐 官方建议用 ConcurrentHashMap 替代 Hashtable

两者都不支持 null 键,如果必须用 null,考虑 Collections.synchronizedMap(new HashMap<>())(但性能差)

深入细节说明

  • 锁机制差异(最核心区别)
    • Hashtable:几乎所有公共方法(put、get、remove、size 等)头部都直接加了 synchronized,相当于对整个 Hashtable 对象加锁。任意时刻只能有一个线程操作,严重限制并发能力。
    • ConcurrentHashMap(JDK 8):
      • get 操作完全无锁,依赖 Node 字段的 volatile 语义保证可见性。
      • put/remove 操作只锁住对应的桶(bucket),其他桶可以并发操作。
      • 使用 CAS(Compare-And-Swap)无锁操作 + 必要时 synchronized 锁单个桶。
      • 扩容时支持多线程协同转移数据(transfer),进一步提升性能。
  • 迭代器特性
    • Hashtable 的迭代器是 fail-fast 类型的,一经发现并发修改就立刻抛异常。
    • ConcurrentHashMap 的迭代器是弱一致性(weakly consistent),遍历过程中如果有其他线程修改,迭代器会尽量反映最新的数据,不会抛异常。这在高并发日志、监控统计等场景非常有用。
  • null 值处理
    • Hashtable:键和值都不能为 null,put(null) 会直接抛 NullPointerException。
    • ConcurrentHashMap:键不能为 null(会抛 NullPointerException),但值可以为 null。
  • 历史演进
    • JDK 7 的 ConcurrentHashMap 使用 Segment 分段锁(默认 16 段)。
    • JDK 8 彻底重构,放弃 Segment,改为更细粒度的桶级锁 + 红黑树优化(链表 >8 转树),性能和内存利用率都大幅提升。

代码对比示例

java 复制代码
// Hashtable 示例(所有操作都加锁)
Hashtable<String, Integer> hashtable = new Hashtable<>();
hashtable.put("key", 1);
Integer value = hashtable.get("key");

// ConcurrentHashMap 示例(get 无锁,put 只锁对应槽)
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("key", 1);
Integer value = concurrentMap.get("key");  // 高并发下极快

总结

Hashtable 是 Java 早期粗粒度同步的产物,已被时代淘汰;ConcurrentHashMap 是现代高并发设计的典范,拥有更高的吞吐量、更细的锁粒度、更友好的迭代器和更好的扩容机制。

生产环境中的最佳实践永远优先使用 ConcurrentHashMap,彻底抛弃 Hashtable

相关推荐
汉字萌萌哒44 分钟前
2024CSP-J入门级C++真题详解
开发语言·c++
arbboter1 小时前
【网络工具】NetProxy网络代理用户手册
开发语言·网络·c#·网络代理·网络异常·代理工具
极创信息1 小时前
系统安全隐患全方位排查方案:标准化渗透测试全流程
java·opencv·struts·数据挖掘·eclipse·语音识别·hibernate
汉字萌萌哒2 小时前
2019CCF-CSP入门级C++试题解析
java·开发语言·c++
叠层归一研究院2 小时前
AGI 系统(十一):二阶网络 — 二阶递归 × 多主体 (元符号网络)
开发语言·人工智能·算法·php·agi
喜欢的名字被抢了2 小时前
程序出问题怎么查,以及如何让它不掉线
java·运维·数据库
小雨笙笙2 小时前
C语言:变量三属性——存储类型
c语言·开发语言
数据知道3 小时前
反序列化漏洞:Java、PHP、Python 三条线各讲透
java·网络·python·安全·网络安全·php
果果燕3 小时前
C++ 学习笔记(二):类与对象—— 构造函数与析构函数
开发语言·c++
江畔柳前堤3 小时前
Function Calling 与 Tool Calling:从认知到工程的全景深度解析
开发语言·网络·人工智能·深度学习·算法·机器学习·php