Hashtable 与 ConcurrentHashMap 的区别是什么?
以下是 Hashtable 与 ConcurrentHashMap 的详细全面对比分析,包括设计理念、实现原理、性能差异、使用场景等,并附上实战建议和源码说明。
一、Hashtable 与 ConcurrentHashMap 总体对比表
| 特性 | Hashtable | ConcurrentHashMap |
|---|---|---|
| 是否线程安全 | 是(全方法同步) | 是(分段锁或CAS机制,粒度更细) |
| 锁机制 | 粗粒度锁:方法级 synchronized | 精细化锁:每个桶/段使用锁或 CAS 操作 |
| 是否允许 null key/value | 全部不允许 | key 不允许,value 允许为 null |
| 性能 | 较低:因全方法锁,存在阻塞 | 高性能:高并发环境表现优越 |
| 引入版本 | JDK 1.0 | JDK 1.5 |
| 推荐使用 | 已不推荐使用 | 现代并发 Map 推荐使用 |
| 迭代器 fail-fast 特性 | 枚举不 fail-fast,易出现并发问题 | fail-fast,能感知并发修改 |
| 支持 Java 8+ 红黑树优化 | 不支持 | 支持 bucket 链表转为红黑树(提升查找效率) |
| 应用场景 | 遗留代码,轻量线程场景 | 多线程高并发环境,线程池、缓存、共享数据等 |
二、线程安全机制详解
1. Hashtable: 方法级锁
public synchronized V get(Object key) { ... }
public synchronized V put(K key, V value) { ... }
所有方法都加
synchronized,导致高并发下线程阻塞严重,无论是否访问同一 key 都会串行化。
2. ConcurrentHashMap: 分段锁 / CAS
Java 7 及之前版本:
- 使用 Segment(分段)锁机制
- 每段相当于一个小的
Hashtable,锁粒度小,多个线程可同时访问不同 Segment
Java 8 及之后版本(主要使用):
- 摒弃了 Segment,采用:
- 数组 + 链表/红黑树
- Node 节点的 synchronized + CAS + volatile
- 提供 更高性能和更小锁竞争
// putVal 内部伪代码
if (tabAt(table, i) == null) {
CAS 插入首个节点;
} else {
synchronized (bucket) {
// 链表或红黑树插入操作
}
}
更适用于 高并发环境(Web服务器、缓存、线程池数据传递等)。
三、为什么不再推荐使用 Hashtable
- 设计太早,未考虑高并发性能
- 全方法同步效率低下
- 没有
ConcurrentModificationException,并发下数据不一致风险大 - 现代项目几乎都使用
ConcurrentHashMap替代
四、实战使用建议
推荐使用 ConcurrentHashMap 替代场景
| 使用场景 | 推荐做法 |
|---|---|
| 线程间共享缓存 | 使用 ConcurrentHashMap 做缓存 Map |
| Web 项目中的会话数据 | 用 ConcurrentHashMap 存储线程隔离数据 |
| 需要高性能、高并发读写操作 | ConcurrentHashMap 是最佳选择 |
| 想避免锁带来的性能损耗 | 利用其非阻塞或局部锁机制,提升吞吐量 |
五、示例代码对比
1. Hashtable 示例
Hashtable<String, String> table = new Hashtable<>();
table.put("key", "value");
System.out.println(table.get("key"));
2. ConcurrentHashMap 示例
ConcurrentHashMap<String, String> cmap = new ConcurrentHashMap<>();
cmap.put("key", "value");
System.out.println(cmap.get("key"));
在高并发情况下,ConcurrentHashMap 支持同时多个线程对不同 key 的并发访问,性能提升巨大。
六、深入资料推荐
| 内容 | 链接 |
|---|---|
| 官方 Javadoc | Hashtable |
| 官方 Javadoc | ConcurrentHashMap |
| 源码分析文章 | Java ConcurrentHashMap 源码解析 |
| 性能对比实测 | Hashtable vs ConcurrentHashMap 性能对比 |
总结一句话
除非维护非常老的遗留系统,否则应全面淘汰
Hashtable,使用ConcurrentHashMap来构建线程安全的 Map。
更多详细内容请关注其他相关文章!