题 HashMap和Hashtable之间的区别?


a之间有什么区别? HashMap 和a Hashtable 在Java?

哪个非线程应用程序更有效?


3122
2017-09-02 20:12


起源


HashTable在Java 1.7中已经过时,建议使用ConcurrentMap实现 - MissFiona


答案:


两者之间存在一些差异 HashMap 和 Hashtable 在Java中:

  1. Hashtable 是 同步,而 HashMap 不是。这使得 HashMap 对于非线程应用程序更好,因为非同步对象通常比同步对象执行得更好。

  2. Hashtable 不允许 null 键或值。 HashMap 允许一个 null 钥匙和任意数量的 null 值。

  3. HashMap的子类之一是 LinkedHashMap,所以如果您想要可预测的迭代顺序(默认情况下是插入顺序),您可以轻松地换出 HashMap 为一个 LinkedHashMap。如果你使用的话,这并不容易 Hashtable

由于同步对您来说不是问题,我建议 HashMap。如果同步成为问题,您也可以查看 ConcurrentHashMap


3207
2017-09-02 23:02



如果您想使HashMap线程安全,请使用 Collections.synchronizedMap()。 - Rok Strniša
我也会评论一下天真的线程安全方法 Hashtable (“同步每个方法应该处理任何并发问题!”)非常有用 更差 用于线程应用程序外部同步你最好 HashMap (并考虑后果),或使用 ConcurrentMap 实现(并利用其扩展的API进行并发)。底线:使用的唯一理由 Hashtable 是遗产API(来自大约1996年)需要它。 - erickson
HashMap为程序员提供了在实际使用时编写threadSafe代码的灵活性。我很少需要一个像ConcurrentHashMap或HashTable这样的线程安全集合。我需要的是同步块中的某些函数或某些语句是线程安全的。 - Gaurava Agarwal
Hashtable已经过时,我们将HashMap用于非线程安全环境。如果您需要线程安全,那么您可以使用Collections.synchronizedMap()或使用ConcurrentHashMap,它比哈希表更有效。 - Maneesh Kumar
它已经过时但没有被弃用,我想知道为什么会这样。我猜测删除这个类(和Vector出于同样的原因)会破坏太多的现有代码并且使用@Deprecated进行注释意味着有意删除代码,这显然不存在。 - Jilles van Gurp


请注意,许多答案表明Hashtable已同步。 在实践中,这很少给你买。  访问器/ mutator方法上的同步将阻止两个线程同时添加或从地图中删除,但在现实世界中,您经常需要额外的同步。

一个非常常见的习语是“检查然后放” - 即在地图中查找条目,如果它尚不存在则添加它。无论您使用Hashtable还是HashMap,这都不是原子操作。

可以通过以下方式获得等效同步的HashMap:

Collections.synchronizedMap(myMap);

但要正确实现这个逻辑,你需要 额外的同步 形式:

synchronized(myMap) {
    if (!myMap.containsKey("tomato"))
        myMap.put("tomato", "red");
}

即使迭代Hashtable的条目(或Collections.synchronizedMap获得的HashMap)也不是线程安全的,除非您还通过其他同步保护Map不被修改。

实施 ConcurrentMap 界面(例如 的ConcurrentHashMap通过包括解决一些这个问题 线程安全检查然后行为语义 如:

ConcurrentMap.putIfAbsent(key, value);

583
2017-09-03 11:00



另请注意,如果修改了HashMap,则指向它的迭代器将变为无效。 - Chris K
Iterator会抛出ConcurrentModificationException,对吧? - Bhushan
那么在线程安全方面,synchronized(myMap){...}和ConcurrentHashMap之间有什么区别吗? - telebog
非常的,我试着在这里解释一下..lovehasija.com/2012/08/16/... - Love Hasija
@Bhushan:它会尽力而为,这不是保证行为: docs.oracle.com/javase/7/docs/api/java/util/HashMap.html - Matt Stephenson


Hashtable 被认为是遗留代码。什么都没有 Hashtable 无法使用 HashMap 的推导 HashMap,所以对于新代码,我认为没有任何理由回到 Hashtable


288
2018-06-25 01:46



来自Hashtable javadoc(重点补充):“从Java 2平台v1.2开始,这个类被改进以实现Map接口, 使其成为Java Collections Framework的成员“但是,你是正确的,它是遗留代码。使用Collections.synchronizedMap(HashMap)可以更有效地获得同步的所有好处。(类似于Vector是Collections.synchronizedList(ArrayList)的遗留版本。) - Kip
@ aberrant80:遗憾的是你在两者之间别无选择,在为J2ME编程时必须使用Hashtable ... - pwes
这个答案应该删除。它包含不正确的信息,并有很多upvotes。 - anon58192932
@ anon58192932是否可以编辑问题来修复它? - GC_
我们必须通过标记来引起海报@ aberrant80或管理员的注意。标记可能会有所帮助 - 现在就试试吧。 - anon58192932


在访谈中经常会询问这个问题,以检查候选人是否理解收集类的正确用法,并了解可用的替代解决方案。

  1. HashMap类大致相当于Hashtable,除了它是非同步的并且允许空值。 (HashMap允许空值作为键和值,而Hashtable不允许空值)。
  2. HashMap不保证地图的顺序会随着时间的推移保持不变。
  3. HashMap是非同步的,而Hashtable是同步的。
  4. HashMap中的迭代器是故障安全的,而Hashtable的枚举器不是,如果任何其他线程通过添加或删除除Iterator自己的remove()方法之外的任何元素而在结构上修改地图,则抛出ConcurrentModificationException。但这不是一种保证行为,将由JVM尽最大努力完成。

关于一些重要条款的说明

  1. 同步意味着只有一个线程可以在一个时间点修改哈希表。基本上,这意味着在对哈希表执行更新之前的任何线程都必须获取对象的锁定,而其他线程将等待锁定被释放。
  2. 故障安全与迭代器的上下文相关。如果已在集合对象上创建了迭代器,并且某些其他线程尝试“在结构上”修改集合对象,则将引发并发修改异常。其他线程可以调用“set”方法,因为它不会“在结构上”修改集合。但是,如果在调用“set”之前,集合已经在结构上进行了修改,则会抛出“IllegalArgumentException”。
  3. 结构修改意味着删除或插入可以有效改变地图结构的元素。

HashMap可以同步

Map m = Collections.synchronizeMap(hashMap);

Map提供了Collection视图,而不是直接支持迭代  通过枚举对象。集合视图大大增强了  界面的表现力,如本节后面所述。  Map允许您迭代键,值或键值对;  Hashtable不提供第三种选择。 Map提供了一种安全的方式  删除迭代中的条目; Hashtable没有。  最后,Map修复了Hashtable界面中的一个小缺陷。  Hashtable有一个名为contains的方法,如果是,则返回true  Hashtable包含给定值。鉴于它的名字,你会期待这一点  如果Hashtable包含给定键,则返回true的方法,因为  关键是Hashtable的主要访问机制。地图  接口通过重命名方法消除了这种混淆的来源  中的containsValue。此外,这提高了界面的一致性 -  containsValue parallels containsKey。

地图界面


148
2017-10-04 06:39



这个答案包含至少2个重要的事实不准确。它当然不值得这么多赞成。 - Stephen C
1)HashMap的迭代器不是故障安全的。他们失败快。这两个术语之间的含义存在巨大差异。 2)没有 set 操作上 HashMap。 3) put(...) 操作不会抛出 IllegalArgumentException 如果有先前的变化。 4)快速失败的行为 HashMap  也 如果您更改映射,则会发生。 5)快速失败的行为 是 保证。 (不保证的是a的行为 HashTable 如果您进行并发修改。实际行为是......不可预测的。) - Stephen C
6) Hashtable 不保证地图元素的顺序也会随时间稳定。 (你可能会感到困惑 Hashtable 同 LinkedHashMap。) - Stephen C
其他任何人都非常担心这些天学生们错误地认为收集集合的“同步版本”意味着您不必外部同步复合操作?这是我最喜欢的例子 thing.set(thing.get() + 1); 通常情况下完全不受保护,尤其是如果完全没有保护的话,这通常会让新手感到惊讶 get() 和 set() 是同步方法。他们中的许多人都期待着魔力。
HashMap上的迭代器不是故障安全的 - Abdul


HashMap:一个实现 Map 使用哈希码索引数组的接口。 Hashtable:嗨,1998年叫。他们想要回收他们的集合API。

说真的,你最好远离 Hashtable 共。对于单线程应用程序,您不需要额外的同步开销。对于高度并发的应用程序,偏执同步可能会导致饥饿,死锁或不必要的垃圾收集暂停。就像Tim Howland指出的那样,你可以使用 ConcurrentHashMap 代替。


107
2017-09-02 23:14



这实际上是有道理的。 ConcurrentHashMaps为您提供了同步自由,调试更加轻松。 - prap19


请记住 HashTable 是Java集合框架(JCF​​)引入之前的遗留类,后来被改进以实现 Map 接口。那是 Vector 和 Stack

因此,在新代码中始终远离它们,因为JCF中总是有更好的替代方案 正如其他人指出的那样。

这里是 Java集合备忘单 你会发现有用的。请注意,灰色块包含遗留类HashTable,Vector和Stack。

enter image description here


104
2018-03-25 08:58





除了izb所说的, HashMap 允许空值,而 Hashtable才不是。

另请注意 Hashtable 扩展了 Dictionary 上课,作为 的Javadoc 国家,已经过时,已被取代 Map 接口。


58
2017-09-02 20:30



但这不会使HashTable过时吗? - Pacerier


看看这张图表。它提供了不同数据结构与HashMap和Hashtable之间的比较。比较准确,清晰,易于理解。

Java Collection Matrix


50
2017-11-20 05:35



谢谢,现在我知道在我的场景中要选择什么。 - Well Smith