如何处理ConcurrentModificationException

我从冷却计时器得到一个ConcurrentModificationException。 我使用线程每秒减少值,如下所示:

public class CoolDownTimer implements Runnable { @Override public void run() { for (String s : playerCooldowns.keySet()) { playerCooldowns.put(s, playerCooldowns.get(s) - 20); if (playerCooldowns.get(s) <= 0) { playerCooldowns.remove(s); } } } } 

所以每一秒都应该将每个玩家的冷却时间减少20,但问题是我在运行程序时每隔几个小时就会获得一次CME,特别是当很多人在线时。 如何使它如果仍在修改列表,它将等到当前操作完成并创建一种修改队列? 谢谢! 这是堆栈跟踪:

 2012-06-18 20:59:05 [WARNING] Task of 'SurvivorsClasses' generated an exception java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:839) at java.util.HashMap$KeyIterator.next(HashMap.java:874) at me.zachoooo.survivorclasses.CoolDownManager$CoolDownTimer.run(CoolDownManager.java:13) at org.bukkit.craftbukkit.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:126) at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:533) at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:459) 

第13行是for循环的开始……

使用foreach循环时无法修改集合。

但是,您可以迭代Map.entrySet()并执行您需要的所有操作:

 public void run() { for (Iterator> i = playerCooldowns.entrySet().iterator(); i.hasNext();) { Map.Entry entry = i.next(); entry.setValue(entry.getValue() - 20); // update via the Map.Entry if (entry.getValue() <= 0) { i.remove(); // remove via the iterator } } } 

当您尝试修改Collection的内容时,抛出ConcurrentModificationException ,同时Iterating它。

阅读本文以及此内容以获得更多讨论。

文档中清楚地提到了有时它可能对您有用的原因。

 The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future. Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. 

Unlike ArrayCollections 编译期间检查 ,而不是运行时检查 ,这就是你无法在循环中修改put(如put()或remove()的原因)