1

目前我的代码导致间歇性 ConcurrentModificationException 错误,可能是因为我循环遍历 HashMap 的方式:

for (Map.Entry<String, Entity> entry : entities.entrySet()) {
    String key = entry.getKey();
    Entity item = entry.getValue();
    if (item.isDestroyed()){
        entities.remove(key);
        ViewManager.getInstance().removeItem(key);
        //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
    } else {
        item.update(1);
        ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
        ViewManager.getInstance().updateItem(ci);                    
    }

    item.update(1);
}
// updateInfo call
ViewManager.getInstance().updateInfo(summary());
}

如何连续循环遍历 HashMap 并避免 ConcurrentModificationException 错误?

4

5 回答 5

5

循环时不能修改地图。您必须制作地图的副本,使用ConcurrentHashMap或使用迭代器。如果它在多线程环境中,那么您可以在同步块中进行修改。

另一种选择是使用迭代器

我用下面的迭代器重写了你的 for for 循环:

for(Iterator<Map.Entry<String, Entity>> iterator = entities.entrySet().iterator(); iterator.hasNext(); ){
    Map.Entry<String, Entity> entry = iterator.next();
    String key = entry.getKey();
    Entity item = entry.getValue();
    if (item.isDestroyed()){
        //Notice using an iterator to remove 
        iterator.remove();
        ViewManager.getInstance().removeItem(key);
        //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
    } else {
        item.update(1);
        ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
        ViewManager.getInstance().updateItem(ci);                    
    }

    item.update(1);

}

我不确定连续循环 HashMap 的部分。哈希映射具有有限的键集,因此您通常会遍历键集。如果您出于某种原因想要连续循环,那么您需要首先告诉我们其背后的原因以及该连续循环的终止条件(它不能真的永远,可以吗?)。

于 2011-10-12T02:19:53.377 回答
3

如其他答案中所述,使用基于迭代器的 for 循环而不是 for-each 循环是避免 ConcurrentModificationExemptions 的最佳选择。至于无限循环,请看 Guava 的 Iterators 静态实用程序类中的循环方法。它接受一个 Iterable(例如 HashMap)并返回一个迭代器,该迭代器不断循环数据,直到 Iterable 为空或您中断循环。

于 2011-10-12T02:58:48.207 回答
1

使用迭代器和while循环怎么样?

Iterator<String> iterator = map.iterator();
String key;
String value;
while (iterator.hasNext()) {
 key = iterator.next();
 value = map.get(key);
}
于 2011-10-12T02:25:56.673 回答
1

循环时不能调用 remote(key) 方法,但可以通过迭代器删除条目:

Map<String, String> map = new HashMap<String, String>();
map.put("one", "1");
map.put("two", "2");
map.put("three", "3");

for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext();)
{
    Map.Entry<String, String> curEntry = i.next();
    if (curEntry.getKey().equals("two"))
        i.remove();
}
于 2011-10-12T02:28:54.643 回答
0

假设您仅在线程上访问地图,请按照其他人的建议使用迭代器。

我在考虑迭代 hashmap 时的性能,所以我对 10^6 个随机 Long 的 25 次迭代进行了快速测试,然后使用不同的 map 实现删除了 10%:ConcurrentHashMap、HashMap、LinkedHashMap 和 TreeMap。

链接的哈希图据说是为迭代量身定制的,它似乎是最有效的。我想尖峰是由于gc。

...但差异比我预期的要小。

在此处输入图像描述

于 2011-10-12T06:55:21.233 回答