Hashtable 与 HashMap 的区别笔记

在 Java 中,Hashtable 和 HashMap 都是用于存储键值对的哈希表实现类,继承自 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 迭代器,虽然 Hashtable 的 keySet() 和 entrySet() 方法返回的是 Iterator,但它的底层实现是基于 Enumerator 的。
  • Enumerator 是在 Vector 和 Hashtable 中早期使用的一种迭代机制,但它已经过时,不支持 remove() 操作,也没有在迭代时抛出 ConcurrentModificationException 异常。

4.2 HashMap

  • HashMap 使用的是现代的 Iterator,它支持快速失败机制(fail-fast),即当集合结构在迭代过程中被修改时,会抛出 ConcurrentModificationException 异常。
  • 迭代时,如果其他线程在修改 HashMap,Iterator 会抛出异常。
小结:
  • 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,它提供了更好的并发性能和线程安全性。
相关推荐
荣码5 小时前
从0到1搭一个生产级RAG系统:串联前面21篇所有知识
java·python
xuxigifxfh5 小时前
牛客:HJ170 01序列
java·开发语言·算法·华为机考
AOI小白新手上路6 小时前
单幅图像去雨·论文蒸馏笔记:统一评测、方法谱系与 HQ-RAIN 新基准
笔记
野生技术架构师6 小时前
牛客网互联网大厂 Java 高频面试题整理(持续更新)
java·开发语言
殷色玫瑰6 小时前
AVL树:从平衡因子到四种旋转的完整实现
c语言·数据结构·c++·算法·visualstudio
糖炒栗子要加糖6 小时前
Windows 大量小文件复制太慢?使用 Robocopy 多线程加速
笔记·提升效率
小师兄吃牛肉6 小时前
Java语法 | 多重循环
java·开发语言·python
2601_961146206 小时前
我的等离子表面处理设备周度保养折腾记录
笔记·设备·设备选型
Han.miracle6 小时前
MySQL InnoDB:MVCC、记录锁、间隙锁、二级索引MVCC底层原理
java·开发语言
小新科研测评7 小时前
文献管理工具同步太麻烦?2026年4款多端同步工具实测,换设备不丢笔记
论文阅读·人工智能·笔记·ai·电脑