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;
此行为并非特定于 Map
s。 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
(内部使用KeyIterator
,ValueIterator
, 等.. 内部), ArrayList
(使用 AbstractList
中的 Iterator
), 等..
HashMap 的 Iterator 与 ConcurrentHashMap 的 Iterator 实现不同。
HashMap的Iterator维护一个版本号(expectedModCount
)并验证checkForComodification()
如下图:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
因此,在迭代的中间,如果基础集合大小被修改(通过 adding/removing 个元素),那么 Iterator
抛出 ConcurrentModificationException
,如上所示。
因为 ConcurrentHashMap
的 Iterator
实现不执行上述检查,所以它不会抛出 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
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;
此行为并非特定于 Map
s。 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
(内部使用KeyIterator
,ValueIterator
, 等.. 内部), ArrayList
(使用 AbstractList
中的 Iterator
), 等..
HashMap 的 Iterator 与 ConcurrentHashMap 的 Iterator 实现不同。
HashMap的Iterator维护一个版本号(expectedModCount
)并验证checkForComodification()
如下图:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
因此,在迭代的中间,如果基础集合大小被修改(通过 adding/removing 个元素),那么 Iterator
抛出 ConcurrentModificationException
,如上所示。
因为 ConcurrentHashMap
的 Iterator
实现不执行上述检查,所以它不会抛出 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