HashMap 不同步那么并发修改异常的原因

HashMap is not synchronized then why concurrentmodification exception

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

ConcurrentHashMap 也不会抛出这个异常。

Iterator 实现是否因不同的数据结构而不同,或者这些数据结构中的某些方法抛出 ConcurrentModificationException

如果 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;

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

不要误以为 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.

Is Iterator implementation different for different datastructures or there is someone method within these data structures which throw ConcurrentModificationException ?

是的,Collection classes.

中有不同的 Iterator 实现

例如,HashMap class(内部使用HashIterator),ConcurrentHashMap(内部使用KeyIteratorValueIterator, 等.. 内部), ArrayList (使用 AbstractList 中的 Iterator), 等..

HashMap 的 Iterator 与 ConcurrentHashMap 的 Iterator 实现不同。

HashMap的Iterator维护一个版本号(expectedModCount)并验证checkForComodification()如下图:

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

因此,在迭代的中间,如果基础集合大小被修改(通过 adding/removing 个元素),那么 Iterator 抛出 ConcurrentModificationException,如上所示。

因为 ConcurrentHashMapIterator 实现不执行上述检查,所以它不会抛出 ConcurrentModificationException。也可以从API中找到相同点 ConcurrentHashMap here.

They (ConcurrentHashMaps) do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.

由于 HashMap 是一个 fail-fast 集合(java.util 包下的所有集合都是 fail fast),如果对结构或键进行任何修改,迭代器将抛出异常,主要是在 Hashmap 的情况下。

我们在 Hashmap 中有一个变量,用于计算 Map.and 中的修改次数,使用该迭代器跟踪对集合所做的修改次数。

transient volatile int modCount;

请阅读下面link:差异解释得很好: Java Modcount (ArrayList) 好的例子: http://www.journaldev.com/122/java-concurrenthashmap-example-iterator