目录

一、先搞懂:三者的“出身”和核心定位

1. HashMap(JDK1.2 出现)

2. HashTable(JDK1.0 出现)

3. ConcurrentHashMap(JDK1.5 出现)

二、核心区别详解(重点,面试必问)

1. 线程安全性(最核心区别)

2. 底层实现与锁机制

3. 允许的键值(null)

4. 并发效率

5. 扩容机制

6. 迭代器特性(快速失败 vs 安全失败)

三、一张表看懂所有区别(面试直接背)

四、实际开发怎么选?(重点,落地性强)

五、总结(通俗好记)


在 Java 集合框架中,HashTable、HashMap、ConcurrentHashMap 都是基于哈希表实现的键值对存储结构,日常开发、面试中经常被问到它们的区别。很多人容易记混,尤其是后两者的并发特性,今天就从基础到进阶,把三者的区别讲透,没有复杂术语,适合新手复习巩固。

先给大家一个核心定位,一句话分清三者的核心差异,记牢这个,后面的细节就好理解了:

HashMap:非线程安全,效率高,日常单线程场景首选;

HashTable:线程安全,但效率极低,基本被淘汰;

ConcurrentHashMap:线程安全,效率高,并发场景首选。

下面我们从「线程安全」「底层实现」「使用场景」等核心维度,一步步拆解,结合实际使用感受,避免干巴巴的对比。

一、先搞懂:三者的“出身”和核心定位

在讲区别之前,先明确三者的基本定位,知道它们各自是为了解决什么问题而生的,后续的区别就顺理成章了。

1. HashMap(JDK1.2 出现)

最基础、最常用的哈希表实现,核心目标是「高效存储和查询」,完全不考虑线程安全。它的设计初衷就是单线程场景下使用,所以没有任何锁机制,效率最高,但多线程并发修改时,会出现数据错乱、死循环等问题(比如扩容时的环形链表)。

日常开发中,只要没有多线程修改操作,比如单线程读取配置、存储临时数据,用 HashMap 就够了,简单、高效、轻量。

2. HashTable(JDK1.0 出现)

比 HashMap 出现得早,核心目标是「解决线程安全问题」,但它的实现方式很“粗暴”——给整个哈希表加了一把全局锁(synchronized 修饰方法)。也就是说,不管多个线程操作的是哈希表的哪个位置,都会竞争同一把锁,一个线程执行,其他所有线程都要阻塞等待。

这种方式虽然保证了线程安全,但效率极低,尤其是并发量高的时候,所有线程排队执行,相当于“单线程运行”,所以现在基本被淘汰,日常开发中很少用到,除非是极其古老的项目。

3. ConcurrentHashMap(JDK1.5 出现)

既然 HashMap 非线程安全,HashTable 效率低,ConcurrentHashMap 就应运而生了——它兼顾了「线程安全」和「高效并发」。它的核心思路是“分段锁”(JDK1.8 优化为 CAS + synchronized 局部锁),不再是全局锁,而是给哈希表的不同分段(或节点)加锁,多个线程操作不同分段时,互不干扰,可以并行执行,大大提升了并发效率。

现在的并发场景,比如多线程读写缓存、处理请求数据,基本都用 ConcurrentHashMap,是三者中最实用、最常用的。

二、核心区别详解(重点,面试必问)

下面从 6 个关键维度,对比三者的差异,结合通俗解读,不用死记硬背,理解背后的逻辑即可。

1. 线程安全性(最核心区别)

  • HashMap非线程安全。多线程并发修改(比如 put、remove)时,会出现数据覆盖、死循环(JDK1.7 及之前)、ConcurrentModificationException(快速失败)等问题;即使是多线程读取,也可能读到脏数据(因为没有可见性保证)。

  • HashTable线程安全。所有方法都用 synchronized 修饰,全局一把锁,保证同一时刻只有一个线程操作整个哈希表。但正因为全局锁,并发效率极低。

  • ConcurrentHashMap线程安全。JDK1.7 用“分段锁”(Segment),将哈希表分成多个分段,每个分段一把锁,多线程操作不同分段可并行;JDK1.8 优化为“CAS + synchronized 局部锁”,只给当前操作的节点加锁,并发效率进一步提升,比 HashTable 高一个量级。

补充:HashMap 不是完全不能用于多线程,比如多线程只读(不修改),或者用 Collections.synchronizedMap() 包装后使用,但包装后的效率不如 ConcurrentHashMap。

2. 底层实现与锁机制

  • HashMap:JDK1.7 是“数组 + 链表”; JDK1.8 优化为“数组 + 链表 + 红黑树”(当链表长度超过 8 时,转为红黑树,提升查询效率);无锁机制,完全依赖单线程环境保证安全。

  • HashTable:底层是“数组 + 链表”(始终没有红黑树优化);全局锁(synchronized 修饰方法),锁粒度极大。

  • ConcurrentHashMap

    • JDK1.7:数组 + Segment(分段)+ 链表,每个 Segment 是一个独立的哈希表,各自有一把锁,锁粒度是“分段”;

    • JDK1.8:去掉 Segment,改为“数组 + 链表 + 红黑树”,锁粒度是“节点”(只锁当前操作的链表/红黑树节点),用 CAS 保证原子性,synchronized 保证节点锁,效率更高。

3. 允许的键值(null)

这是一个容易忽略的细节,日常使用中很容易踩坑:

  • HashMap:允许键为 null,允许值为 null(键只能有一个 null,值可以有多个 null);

  • HashTable:不允许键为 null,也不允许值为 null,否则会抛出 NullPointerException;

  • ConcurrentHashMap:不允许键为 null,也不允许值为 null(和 HashTable 一致),因为并发场景下,null 会导致无法判断是“键不存在”还是“值为 null”,容易出现逻辑错误。

4. 并发效率

效率排序(从高到低):ConcurrentHashMap > HashMap > HashTable

  • HashMap:无锁,单线程下效率最高,多线程下不安全,无法用于并发修改;

  • ConcurrentHashMap:锁粒度小,多线程并发时,可并行操作不同分段/节点,效率接近 HashMap;

  • HashTable:全局锁,多线程并发时,所有线程排队,效率最低,基本被淘汰。

5. 扩容机制

  • HashMap:初始容量 16,负载因子 0.75,扩容时容量翻倍(16→32→64...),JDK1.7 扩容时会出现环形链表(死循环),JDK1.8 修复了这个问题;

  • HashTable:初始容量 11,负载因子 0.75,扩容时容量翻倍 +1(11→23→47...),扩容效率低,且全局锁会导致扩容期间所有线程阻塞;

  • ConcurrentHashMap:JDK1.7 中,每个 Segment 独立扩容,互不干扰;JDK1.8 扩容时,采用 CAS + 多线程协助扩容,效率比 HashTable 高很多,且不影响其他线程的读写操作。

6. 迭代器特性(快速失败 vs 安全失败)

  • HashMap:迭代器是“快速失败”(fail-fast),迭代过程中,如果其他线程修改了哈希表(put、remove),会抛出 ConcurrentModificationException;

  • HashTable:迭代器是“快速失败”,和 HashMap 一致;

  • ConcurrentHashMap:迭代器是“安全失败”(fail-safe),迭代过程中,其他线程可以修改哈希表,不会抛出异常,因为迭代器遍历的是副本数据,而非原始数据。

三、一张表看懂所有区别(面试直接背)

对比维度

HashMap

HashTable

ConcurrentHashMap

线程安全

非线程安全

线程安全(全局锁)

线程安全(分段锁/CAS+局部锁)

底层实现(JDK1.8)

数组+链表+红黑树

数组+链表

数组+链表+红黑树

允许 null 键/值

允许(键1个,值多个)

不允许

不允许

并发效率

单线程最高,多线程不安全

极低

高(并发首选)

扩容机制

容量翻倍,JDK1.8 修复死循环

容量翻倍+1,效率低

多线程协助扩容,效率高

迭代器特性

快速失败(fail-fast)

快速失败(fail-fast)

安全失败(fail-safe)

适用场景

单线程存储、查询

古老项目,基本淘汰

多线程并发读写、缓存等

四、实际开发怎么选?(重点,落地性强)

不用纠结,记住这3条,直接对应场景选择,不会出错:

  1. 如果是 单线程场景(比如单线程读取配置、处理临时数据):选 HashMap,效率最高,简单易用;

  2. 如果是 多线程并发场景(比如多线程读写缓存、处理请求参数):选 ConcurrentHashMap,兼顾线程安全和效率,是目前的最优解;

  3. 如果是 古老项目维护,遇到 HashTable:不用刻意替换,只要并发量不高,能正常运行就好;新项目绝对不要用 HashTable。

五、总结(通俗好记)

HashMap 是“单线程效率王”,不安全但够用;HashTable 是“老古董”,安全但低效,基本淘汰;ConcurrentHashMap 是“并发全能王”,既安全又高效,是现在并发场景的首选。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐