我有下面的代码,但是我得到了ConcurrentModificationException,我应该如何避免这个问题?(出于某种原因,我不得不使用WeakHashMap )
WeakHashMap<String, Object> data = new WeakHashMap<String, Object>();
// some initialization code for data
for (String key : data.keySet()) {
if (data.get(key) != null && data.get(key).equals(value)) {
//do something to modify the key
}
}发布于 2013-08-06 02:29:55
可能是因为迭代中的// do something实际上正在修改底层集合。
来自ConcurrentModificationException
例如,如果线程在使用失败快速迭代器迭代集合时直接修改集合,迭代器将抛出此异常。
来自(弱)HashMap的keySet()
返回此映射中包含的键的集合视图。集合由映射支持,因此对映射的更改反映在集合中,反之亦然。如果映射是在集合上的迭代正在进行时被修改的(除非通过迭代器自己的移除操作),则迭代的结果是未定义的。
发布于 2020-01-29 05:22:40
用于WeakHashMap的Javadoc类解释了为什么会发生这种情况:
映射不变量不适用于这个类。因为垃圾收集器可以在任何时候丢弃键,所以WeakHashMap的行为可能就像一个未知的线程正在悄悄地删除条目一样。
此外,您使用的增强型for-循环在引擎盖下生成的迭代器具有快速失败的类型,正如javadoc中引用的解释所示。
由这个类的所有“集合视图方法”返回的集合的迭代器返回的迭代器都是失败的:如果在创建迭代器之后的任何时候对映射进行了结构上的修改,那么除非通过迭代器自己的remove方法,否则迭代器将抛出一个ConcurrentModificationException。因此,在并发修改的情况下,迭代器会迅速而干净地失败,而不是在未来某个未定的时间冒着任意的、不确定的行为的风险。
因此,由于以下原因,循环可以抛出此异常:
由于您的意图似乎是处理尚未被GC处理的对象,我建议使用迭代器如下:
Iterator<String> it = data.keySet().iterator();
int count = 0;
int maxTries = 3;
while(true) {
try {
while (it.hasNext()) {
String str = it.next();
// do something
}
break;
} catch (ConcurrentModificationException e) {
it = data.keySet().iterator(); // get a new iterator
if (++count == maxTries) throw e;
}
}发布于 2021-02-11 01:51:15
您可以先克隆密钥集,但请注意,在此之后保存强引用:
Set<KeyType> keys;
while(true) {
try {
keys = new HashSet<>(weakHashMap.keySet());
break;
} catch (ConcurrentModificationException ignore) {
}
}
for (KeyType key : keys) {
// ...
}https://stackoverflow.com/questions/18069750
复制相似问题