-1

I recently bumped into an error when running my runnable which updates the location of minecarts. Main.UvehicleLocation2 is a HashMap

[22:36:59] [Craft Scheduler Thread - 607/WARN]: Exception in thread "Craft Scheduler Thread - 607" 
[22:36:59] [Craft Scheduler Thread - 607/WARN]: org.apache.commons.lang.UnhandledException: Plugin CreativeControlByKubqoA v2.2.3 generated an exception while executing task 3019245
at org.bukkit.craftbukkit.v1_9_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:56)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
at java.util.HashMap$KeyIterator.next(HashMap.java:1453)
at java.util.AbstractCollection.toArray(AbstractCollection.java:141)
at java.util.ArrayList.<init>(ArrayList.java:177)
at me.kubqoa.creativecontrol.tasks.VehiclesUpdateDB.run(VehiclesUpdateDB.java:19)
at org.bukkit.craftbukkit.v1_9_R1.scheduler.CraftTask.run(CraftTask.java:71)
at org.bukkit.craftbukkit.v1_9_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53)
... 3 more

This is the code:

@Override
public void run() {
    List<Location> locations1 = new ArrayList<Location>(Main.UvehiclesLocation2.keySet());
    for (Location location : locations1) {
        VehicleHelper.updateVehicle(location,Main.UvehiclesLocation2.get(location));
    }
}
Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
J. Arbet
  • 503
  • 4
  • 12
  • `Main.UvehiclesLocation2.keySet()` is being changed while you are copying it into the new array list. You'd need exclusive access to that instance while you copy it. (Or use a `ConcurrentHashMap`, for instance). – Andy Turner May 20 '16 at 21:09
  • Like change the type of `UvehiclesLocation2` from `HashMap` to `ConcurrentHashMap`? – J. Arbet May 20 '16 at 21:18
  • Yes. If you need to iterate it and update it at the same time, you can use `ConcurrentHashMap`. In particular [iterating `keySet()`](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html#keySet()) is guaranteed not to throw a `ConcurrentModificationException`. – Andy Turner May 20 '16 at 21:21

1 Answers1

0

Main.UvehiclesLocation2.keySet() is being changed while you are copying it into the new array list.

You either need exclusive access to that instance while you copy it (e.g. using a synchronized block), or you can change Main.UvehiclesLocation2 to be a ConcurrentHashMap instead. From the Javadoc:

The view's iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException, and guarantees to traverse elements as they existed upon construction of the iterator, and may (but is not guaranteed to) reflect any modifications subsequent to construction.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • I changed the type to `ConcurrentHashMap` but now when trying to access the HashMap in another part of code using `if (Main.UvehiclesLocation2.containsKey(location)) location=Main.UvehiclesLocation2.get(location);` it throws error `java.lang.NoSuchFieldError: UvehiclesLocation2` – J. Arbet May 20 '16 at 21:52
  • Sounds like you need to recompile your code. – Andy Turner May 20 '16 at 21:59
  • That does not work, I did the same error. – J. Arbet May 20 '16 at 22:16