登录
首页 >  文章 >  java教程

Hashtable与HashMap线程安全及空值对比

时间:2026-05-26 09:38:20 207浏览 收藏

Hashtable 与 HashMap 的核心差异在于线程安全机制和 null 值处理:Hashtable 通过全方法 synchronized 实现“开箱即用”的线程安全,但性能低下、不支持 null 键值、接口陈旧且已被淘汰;HashMap 轻量高效、允许 null 键值,却完全无并发保护,多线程下易引发死循环、数据丢失或迭代器异常;现代开发中,ConcurrentHashMap 才是线程安全场景的真正首选——它以分段锁或 CAS 实现高并发读写,兼顾性能与安全性,而 Hashtable 仅存在于遗留系统中,新项目使用它几乎等同于技术倒退。

什么是Hashtable_与HashMap在线程安全与Null值处理上的对比

Hashtable 和 HashMap 为什么一个能直接多线程用,一个不行?

因为 Hashtable 每个 public 方法(比如 putgetremove)都加了 synchronized,相当于整张表一把大锁;而 HashMap 完全没这层保护,多个线程同时 put 可能触发扩容+链表循环,JDK 7 甚至会卡死线程。

  • 不是“偶尔出错”,是结构性风险:并发 put 可能导致 get 死循环或数据丢失
  • 别指望“我只读不写”就安全——HashMap 的迭代器(Iterator)是 fail-fast 的,遍历时其他线程一改结构,立刻抛 ConcurrentModificationException
  • 真要线程安全,ConcurrentHashMap 是现代首选,它用分段锁/CAS,读操作完全无锁,性能远超 Hashtable

HashMap 允许 null 键值,Hashtable 一放就崩,原因在哪?

Hashtableput 开头就显式判空:if (key == null || value == null) throw new NullPointerException();而 HashMapnull 键做了特殊哈希处理(固定放在数组第 0 个桶),null 值则完全放行。

  • map.put(null, "ok")HashMap 中合法,在 Hashtable 中直接 NullPointerException
  • 注意陷阱:map.get(null) 返回 null 时,你无法区分是“没这个键”还是“这个键对应值就是 null”——得用 containsKey(null) 单独判断
  • 如果业务逻辑依赖 null 作为有效语义(比如“未设置状态”),Hashtable 直接出局

现在还有必要选 Hashtable 吗?

几乎没有。它被设计出来时连 Collection 框架都没有,继承自已废弃的 Dictionary 类,连 forEachstream 都不支持。

  • 初始容量是 11,扩容是 old * 2 + 1,和 HashMap 的 16→32→64 规则不一致,纯属历史包袱
  • 迭代器不是 fail-fast,改了结构也不报错,反而更难定位并发问题
  • 如果你在维护 JDK 1.0–1.4 的老系统,才可能见到它;新项目里写 Hashtable,会被同事当反模式案例讲

该用哪个 Map?一句话决策树

单线程场景?无脑用 HashMap。需要线程安全?优先 ConcurrentHashMap,实在要锁整个 map 才考虑 Collections.synchronizedMap(new HashMap()) ——但别碰 Hashtable

  • 想存 null 键?只能选 HashMapConcurrentHashMap(它也允许 null 值,但禁止 null 键)
  • ConcurrentHashMap 时注意:computeIfAbsent 等方法内部有锁,回调函数里不要再同步调用自身,容易死锁
  • 最常被忽略的一点:Hashtableelements()keys() 返回的是 Enumeration,不是 Iterator,没法用增强 for 循环,连 lambda 都接不上

以上就是《Hashtable与HashMap线程安全及空值对比》的详细内容,更多关于的资料请关注golang学习网公众号!

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>