HashMap 的迭代器是快速失败的,而 HashTable 的枚举器不是,你到底是啥意思?

Posted

技术标签:

【中文标题】HashMap 的迭代器是快速失败的,而 HashTable 的枚举器不是,你到底是啥意思?【英文标题】:What do you exactly mean by HashMap's iterator is fail-fast and HashTable's enumerator isn't?HashMap 的迭代器是快速失败的,而 HashTable 的枚举器不是,你到底是什么意思? 【发布时间】:2012-02-03 18:37:43 【问题描述】:

我正在查找这两个类之间的区别,这一点出现在很多答案中,这个博客是来源: http://javarevisited.blogspot.com/2010/10/difference-between-hashmap-and.html

但是我不完全明白。 有人可以详细说明吗?也许举个例子?

感谢您的关注!

【问题讨论】:

【参考方案1】:

Fail-fast 意味着当您在迭代时尝试修改内容时,它将失败并抛出 ConcurrentModificationException。

Set keys = hashMap.keySet();
for (Object key : keys) 
    hashMap.put(someObject, someValue); //it will throw the ConcurrentModificationException here
 

对于HashTable枚举:

 Enumeration keys = hashTable.keys();
 while (keys.hasMoreElements()) 
          hashTable.put(someKey, someValue);  //this is ok
    

【讨论】:

Hastable 的迭代器是快速失败的。它的枚举不是。【参考方案2】:

最好的方法可能是查看每个类的源代码,由 Open JDK 实现的每个类实现;这样一来,您就可以直接从马嘴里得到答案:-)

除此之外,从本质上讲,“快速失败”意味着如果检测到另一个线程已修改目标 HashMap,则 HashMap 上的迭代器将抛出异常 - 如果您查看 HashMap 的源代码,您将看到这是通过简单地检查预期修改数量的计数器来完成的。如果修改计数与 Iterator 预期的不同,则意味着自上次检查后有人进入并弄乱了 HashMap,因此 Iterator 抛出 ConcurrentModificationException。

“非快速失败”迭代器不会费心检查,并且会愉快地在底层数据结构中执行其业务。因此,您获得了一些灵活性(在这种情况下可能是可疑的灵活性),以换取以后可能会遇到错误;即尝试访问不再存在的值。

与所有fail-fast 策略一样,其理念是越早检测到错误,就越容易从中恢复或调试。

【讨论】:

不只是另一个线程。如果您在迭代地图时修改地图,即使在同一个线程中,也会引发 ConcurrentModification(除非您使用迭代器本身修改地图) 非常真实!我自己犯的一个有时令人困惑的错误:-)【参考方案3】:

在调用iterator.next() 时,如果在创建迭代器和调用next() 之间进行了任何修改,则会立即抛出 ConcurrentModificationException。这就是快速失败的意思。

Hashtable 返回的枚举没有这种行为。他们假设您知道自己在做什么,并且如果您在使用其枚举之一对其进行迭代时修改地图,他们的行为(AFAIK)是未定义的。

【讨论】:

以上是关于HashMap 的迭代器是快速失败的,而 HashTable 的枚举器不是,你到底是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

HashMap和Hashtable有什么区别?

Java集合--set集合

第一次有人把HashMap的hash快速生成方法这么详细~

几种常见 容器 比较和分析 hashmap, map, vector, list ...hash table

HashMap-JDK源码阅读

JavaSE复习6