HashMap未同步,那么为什么并发修改异常

时间:2016-11-30 08:03:23

标签: java hashmap iterator concurrenthashmap

HashMap不应该是线程安全的,那么如果有人修改了hashMap,为什么迭代器会抛出concurrentmodificationexception

ConcurrentHashMap也不会抛出此异常。

Iterator实现对于不同的数据结构是不同的,或者这些数据结构中有某个方法抛出ConcurrentModificationException

4 个答案:

答案 0 :(得分:3)

当迭代HashMap时修改HashMap的结构(即添加或删除条目)时,迭代器可能会以多种方式失败。

ConcurrentModificationException异常旨在通过此类修改使任何迭代器快速失败。

这是modCount字段的用途:

/**
 * The number of times this HashMap has been structurally modified
 * Structural modifications are those that change the number of mappings in
 * the HashMap or otherwise modify its internal structure (e.g.,
 * rehash).  This field is used to make iterators on Collection-views of
 * the HashMap fail-fast.  (See ConcurrentModificationException).
 */
transient int modCount;

此行为并非特定于Map。在迭代期间修改它们时,Collection也会抛出此异常。

答案 1 :(得分:3)

不要以为Concurrent只涉及多线程。

异常意味着在使用修改前创建的迭代器时,对结构进行了结构修改。该修改可能由不同的线程执行,但它可能与执行迭代的线程相同。

以下单线程代码产生CME:

Map<String, String> map = new HashMap<>();
map.put("a", "a");
map.put("b", "b");

for (String k: map.entrySet()) {
  map.clear();
}

或者,更清楚地显示循环中的迭代器(两个循环是等效的):

Iterator<String> it = map.entrySet().iterator();
while (it.hasNext()) {
  String k = it.next();
  map.clear();
}
it.hasNext()之后调用

map.clear(),结果为ConcurrentModificationException

答案 2 :(得分:0)

  

Iterator实现对于不同的数据结构是不同的   这些数据结构中有某种方法抛出   ConcurrentModificationException?

是的, Iterator类中有不同的Collection实施

例如, HashMap类(内部使用HashIterator),ConcurrentHashMap(内部使用KeyIteratorValueIterator等)< / strong>,ArrayList(使用Iterator中的AbstractList)等。

HashMap的迭代器与ConcurrentHashMap的迭代器实现不同。

HashMap的迭代器维护版本号(expectedModCount)并验证checkForComodification(),如下所示:

final void checkForComodification() {
   if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

因此,在迭代过程中,如果修改了基础集合大小(通过添加/删除元素),则Iterator抛出ConcurrentModificationException,如上所示。

ConcurrentHashMap Iterator实现不执行上述检查的位置,因此它不会抛出ConcurrentModificationException。您还可以在ConcurrentHashMap https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/By.html#id-java.lang.String-

的API中找到相同的点
  

他们(ConcurrentHashMaps)不会抛出ConcurrentModificationException。但是,迭代器   设计为一次只能由一个线程使用。

答案 3 :(得分:0)

由于HashMap是一个快速失败的集合(java.util包下的所有集合都快速失败),如果对Hashmap主要进行结构或键的任何修改,则Iterator抛出异常。

我们在Hashmap中有一个变量来计算Map中的修改数量。使用该迭代器可以跟踪对集合进行修改的数量。

transient volatile int modCount;

请阅读以下链接:差异解释得非常好: Java Modcount (ArrayList) 好例子: http://www.journaldev.com/122/java-concurrenthashmap-example-iterator