![图片[1]-32 ConcurrentHashMap vs Hashtable:同样线程安全,区别在哪?-速优课](http://www.suyouke.com/wp-content/uploads/2026/07/doubao_img_2304x1728_20260726_193128-1024x768.png)
ConcurrentHashMap vs Hashtable:同样线程安全,区别在哪?
📌 本文导读
本文将围绕「同样是线程安全,ConcurrentHashMap 和 Hashtable 的区别」这一主题展开深入探讨。
在Java并发编程的学习过程中,这是一个非常核心且高频的知识点。通过本文的学习,你将能够:
✅ 理解核心概念与原理 ✅ 掌握实际应用场景 ✅ 避开常见的使用陷阱 ✅ 应对面试中的相关问题
在本课时我们主要讲解同样是线程安全,ConcurrentHashMap 与 Hashtable 到底有什么区别呢?
我们都知道 HashMap 不是线程安全的,而 ConcurrentHashMap 和 Hashtable 它们两个确实都是线程安全的,那它们有哪些不同点呢?我们从以下四个角度出发,去分析它们的不同点。
出现的版本不同
我们先从表面的、显而易见的出现时间来分析。Hashtable 在 JDK1.0 的时候就存在了,并在 JDK1.2 版本中实现了 Map 接口,成为了集合框架的一员。而 ConcurrentHashMap 则是在 JDK1.5 中才出现的,也正是因为它们出现的年代不同,而后出现的往往是对前面出现的类的优化,所以它们在实现方式以及性能上,也存在着较大的不同。
实现线程安全的方式不同
虽然 ConcurrentHashMap 和 Hashtable 它们两个都是线程安全的,但是从原理上分析,Hashtable 实现并发安全的原理是通过 synchronized 关键字,让我们直接看下源码,以 clear() 方法为例,代码如下:
public synchronized void clear() {
Entry<?,?> tab[] = table;
modCount++;
for (int index = tab.length; --index >= 0; )
tab[index] = null;
count = 0;
}
可以看出这个 clear() 方法是被 synchronized 关键字所修饰的,同理其他的方法例如 put、get、size 等,也同样是被 synchronized 关键字修饰的。之所以 Hashtable 是线程安全的,是因为几乎每个方法都被 synchronized 关键字所修饰了,这也就保证了线程安全。
Collections.SynchronizedMap(new HashMap()) 的原理和 Hashtable 类似,也是利用 synchronized 实现的。而我们的 ConcurrentHashMap 实现的原理,却有大大的不同,让我们看一下它在 Java 8 中的结构示意图:
![图片[2]-32 ConcurrentHashMap vs Hashtable:同样线程安全,区别在哪?-速优课](https://www.suyouke.com/wp-content/uploads/2026/07/image-96-1024x361.png)
对于 ConcurrentHashMap 的原理,我们在第 30 课时的时候有过详细的介绍和源码分析,本质上它实现线程安全的原理是利用了 CAS + synchronized + Node 节点的方式,这和 Hashtable 的完全利用 synchronized 的方式有很大的不同。
性能不同
正因为它们在线程安全的实现方式上的不同,导致它们在性能方面也有很大的不同。当线程数量增加的时候,Hashtable 的性能会急剧下降,因为每一次修改都需要锁住整个对象,而其他线程在此期间是不能操作的。不仅如此,还会带来额外的上下文切换等开销,所以此时它的吞吐量甚至还不如单线程的情况。
而在 ConcurrentHashMap 中,就算上锁也仅仅会对一部分上锁而不是全部都上锁,所以多线程中的吞吐量通常都会大于单线程的情况,也就是说,在并发效率上,ConcurrentHashMap 比 Hashtable 提高了很多。
迭代时修改的不同
Hashtable(包括 HashMap)不允许在迭代期间修改内容,否则会抛出ConcurrentModificationException 异常,其原理是检测 modCount 变量,迭代器的 next() 方法的代码如下:
public T next() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
return nextElement();
}
可以看出在这个 next() 方法中,会首先判断 modCount 是否等于 expectedModCount。其中 expectedModCount 是在迭代器生成的时候随之生成的,并且不会改变。它所代表的含义是当前 Hashtable 被修改的次数,而每一次去调用 Hashtable 的包括 addEntry()、remove()、rehash() 等方法中,都会修改 modCount 的值。这样一来,如果我们在迭代的过程中,去对整个 Hashtable 的内容做了修改的话,也就同样会反映到 modCount 中。这样一来,迭代器在进行 next 的时候,也可以感知到,于是它就会发现 modCount 不等于 expectedModCount,就会抛出 ConcurrentModificationException 异常。
所以对于 Hashtable 而言,它是不允许在迭代期间对内容进行修改的。相反,ConcurrentHashMap 即便在迭代期间修改内容,也不会抛出ConcurrentModificationException。
本课时总结了 ConcurrentHashMap 与 Hashtable 的区别,虽然它们都是线程安全的,但是在出现的版本上、实现线程安全的方式上、性能上,以及迭代时是否支持修改等方面都有较大的不同,如果我们有并发的场景,那么使用 ConcurrentHashMap 是最合适的,相反,Hashtable 已经不再推荐使用。
🎯 总结与思考
核心要点回顾
通过本文的学习,我们深入探讨了「同样是线程安全,ConcurrentHashMap 和 Hashtable 的区别」相关的知识。主要内容包括:
- 基础概念:从底层原理出发,理解核心概念的本质
- 实现机制:分析源码层面的实现细节
- 应用场景:了解在实际项目中如何正确使用
- 注意事项:掌握常见的坑点与避坑方法
知识延伸
并发编程是Java高级开发必须掌握的核心技能。本文涉及的知识点不仅在日常开发中经常用到,也是各大互联网公司面试的高频考点。建议大家:
- 🔍 结合源码深入理解原理
- 🛠️ 多动手实践,在项目中应用
- 📚 与其他并发知识点串联学习,形成知识体系
- 💡 多思考为什么这么设计,而不只是怎么用
思考问题
- 你在实际项目中遇到过哪些与本文相关的问题?
- 还有哪些场景可以应用本文学到的知识?
- 本文讲解的内容还有哪些可以拓展的方向?
💡 欢迎在评论区留言讨论,一起交流进步!








请登录后查看评论内容