Search code examples
javafor-looprunnableconcurrentmodification

How to deal with ConcurrentModificationException


I am getting the a ConcurrentModificationException from my cooldown timer. I use a thread to reduce the values every second like this:

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);
            }
        }
    }

}

So every second it should reduce every players cooldown by 20, but the problem is that I a getting the CME every couple hours while running the program, especially when lots of people are online. How do I make it so that if it is still modifying the list, it will wait until the current operation is done and create a sort of modification queue? Thanks! Here is the stack trace:

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)

Line 13 is the start of the for loop...


Solution

  • You can't modify collections when using a foreach loop.

    You can however iterate over the Map.entrySet() and do everything you need:

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