Hashtable 与 HashMap 的区别笔记

在 Java 中,HashtableHashMap 都是用于存储键值对的哈希表实现类,继承自 Map 接口。虽然它们都提供了类似的功能,但它们在性能、线程安全性、支持的特性等方面存在一些显著的区别。了解这些差异有助于在开发过程中选择适合的集合类。

1. 线程安全性

1.1 Hashtable

  • Hashtable线程安全 的。在多线程环境下,Hashtable 使用**同步(Synchronized)**机制来确保每次只有一个线程能访问它的内部数据。
  • 这种同步机制会使得 Hashtable 在并发环境下能够避免数据不一致问题,但也会显著影响性能。因为在同一时间只有一个线程能够访问它的任意部分,导致线程在进行读写操作时会发生阻塞。

1.2 HashMap

  • HashMap非线程安全 的。在多线程环境中,多个线程对 HashMap 进行修改时会产生不确定的结果,因此无法保证数据的一致性。
  • 如果需要在多线程环境中使用 HashMap,通常会使用外部同步手段(如 Collections.synchronizedMap()ReentrantLock)来确保线程安全。
小结:
  • Hashtable 是线程安全的,但性能较差。
  • HashMap 是非线程安全的,适合单线程或外部进行同步的情况。

2. 性能

2.1 Hashtable

由于 Hashtable 在每个操作上都进行同步,它在并发环境下会产生额外的性能开销。每次线程需要等待对 Hashtable 的访问,导致并发性能差。

2.2 HashMap

HashMap 由于不进行同步控制,它的性能通常优于 Hashtable,尤其在单线程环境下,或者在使用外部同步机制时。没有同步开销,读取和写入速度较快。

小结:
  • Hashtable 的性能较差,适合较低并发的场景。
  • HashMap 的性能更高,适合高并发的场景(需要外部同步)。

3. 空键和空值的支持

3.1 Hashtable

  • Hashtable 不允许键或值为 null。如果你尝试使用 null 作为键或值插入到 Hashtable 中,将会抛出 NullPointerException 异常。

3.2 HashMap

  • HashMap 允许一个 null 键和多个 null 值。null 键会被存储在哈希表的第一个位置,而多个 null 值则可以正常存储。
小结:
  • Hashtable 不允许 null 键和值。
  • HashMap 允许一个 null 键和多个 null 值。

4. 迭代器的不同

4.1 Hashtable

  • Hashtable 使用的是传统的 Enumerator 迭代器,虽然 HashtablekeySet()entrySet() 方法返回的是 Iterator,但它的底层实现是基于 Enumerator 的。
  • Enumerator 是在 VectorHashtable 中早期使用的一种迭代机制,但它已经过时,不支持 remove() 操作,也没有在迭代时抛出 ConcurrentModificationException 异常。

4.2 HashMap

  • HashMap 使用的是现代的 Iterator,它支持快速失败机制(fail-fast),即当集合结构在迭代过程中被修改时,会抛出 ConcurrentModificationException 异常。
  • 迭代时,如果其他线程在修改 HashMapIterator 会抛出异常。
小结:
  • Hashtable 使用的是过时的 Enumerator,不支持并发修改。
  • HashMap 使用支持并发修改检查的 Iterator

5. 扩容策略

5.1 Hashtable

  • Hashtable 在初次加载时,默认的初始容量为 11,负载因子为 0.75。扩容时会将容量扩大为原来的两倍,并且在扩容过程中会进行同步,导致性能进一步下降。
  • 扩容过程是全表锁定的,可能影响并发性能。

5.2 HashMap

  • HashMap 的默认初始容量为 16,负载因子为 0.75。与 Hashtable 相比,HashMap 在扩容时的效率更高。扩容时会将容量扩大为原来的两倍。
  • HashMap 的扩容也是线程不安全的,但它的性能优于 Hashtable,特别是在扩容操作中不需要全表加锁。
小结:
  • Hashtable 的扩容性能较差,尤其在高并发时。
  • HashMap 的扩容性能更好,适合高并发场景。

6. 类的继承关系

6.1 Hashtable

  • Hashtable 继承自 Dictionary 类,而 Dictionary 是一个过时的类,已经不再推荐使用。
  • Hashtable 实现了 Map 接口,但由于它继承自 Dictionary,其设计较为老旧。

6.2 HashMap

  • HashMap 直接实现了 Map 接口,并且不依赖于 Dictionary 类,是现代 Java 集合框架的标准实现类。
  • HashMap 是基于哈希表的实现,通常比 Hashtable 更灵活和高效。
小结:
  • Hashtable 继承自过时的 Dictionary 类。
  • HashMap 直接实现 Map 接口,符合现代 Java 集合设计。

7. 总结

特性 Hashtable HashMap
线程安全性 线程安全(使用同步) 非线程安全
性能 由于同步机制,性能较差 性能较好,尤其在单线程下
空键和空值支持 不允许 null 键和值 允许 null 键和多个 null
迭代器 使用过时的 Enumerator,不支持并发修改 使用现代的 Iterator,支持并发修改检查
扩容机制 扩容时全表加锁,性能较差 扩容时不加锁,性能优越
类的继承关系 继承自 Dictionary 继承自 Map 接口,符合现代设计

结论

  • 在现代 Java 开发中,Hashtable 已经不再被推荐使用。由于其线程安全的机制,它的性能在高并发场景下不如 HashMap,而且使用过时的 Dictionary 类。
  • HashMap 是更现代、更高效的选择,适用于大多数应用场景,尤其是在单线程环境或通过外部同步确保线程安全的情况下。如果需要线程安全的集合,推荐使用 ConcurrentHashMap,它提供了更好的并发性能和线程安全性。
相关推荐
木木_王3 分钟前
嵌入式Linux学习 | 数据结构 (Day05) 栈与队列详解(原理 + C 语言实现 + 实战实验 + 易错点剖析)
linux·c语言·开发语言·数据结构·笔记·学习
lkforce8 分钟前
MiniMind学习笔记(三)--train_pretrain.py(预训练)
笔记·机器学习·ai·预训练·minimind·train_pretrain
OSwich15 分钟前
【 Godot 4 学习笔记】数组(Array)
笔记·学习·godot
冷雨夜中漫步19 分钟前
Claude Code源码分析——Claude Code Agent Loop 详细设计文档
java·开发语言·人工智能·ai
北顾笙98022 分钟前
day38-数据结构力扣
数据结构·算法·leetcode
m0_6294947323 分钟前
LeetCode 热题 100-----14.合并区间
数据结构·算法·leetcode
直奔標竿24 分钟前
Java开发者AI转型第二十六课!Spring AI 个人知识库实战(五)——联网搜索增强实战
java·开发语言·人工智能·spring boot·后端·spring
数据皮皮侠AI28 分钟前
中国城市可再生能源数据集(2005-2021)|顶刊 Sci Data 11 种能源面板
大数据·人工智能·笔记·能源·1024程序员节
@小码农1 小时前
2026年3月Scratch图形化编程等级考试一级真题试卷
开发语言·数据结构·c++·算法
其实防守也摸鱼1 小时前
面试常问问题总结--护网蓝队方向
网络·笔记·安全·面试·职场和发展·护网·初级蓝队