java.util.AbstractList$Itr.checkForComodification Triple Events
I run a server and it has an event handler that handles a timing system When I run 3 of them in a row, it gives this exception
Exception in thread "Thread-8" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at EventManager.run(EventManager.java:77)
at java.lang.Thread.run(Thread.java:662)
here's the method that the issue is coming from:
EventManager.getSingleton().addEvent( new Event() {
public void execute(EventContainer c) {
p.createProjectile(p.absY, p.absX, offsetY, offsetX, 1166, 43, 31, 70, p2.playerId);
c.stop(); // stops the event from running
}
}, 950); // in ms (1 second = 1000 ms)
EventManager.getSingleton().addEvent( new Event() {
public void execute(EventContainer c) {
p2.applyDAMAGE(misc.random(25));
c.stop(); // stops the event from running
}
}, 1300); // in ms (1 second = 1000 ms)
p.secondsTillNextDfsSpecial = 120;
EventManager.getSingleton().addEvent( new Event() {
public void execute(EventContainer c) {
p.secondsTillNextDfsSpecial--;
if (p.secondsTillNextDfsSpecial == 0) {
p.canPerformDfsSpecial = true;
c.stop(); // stops the event from running
}
}
}, 1000); // in ms (1 second = 1000 ms)
import java.util.ArrayList;
import java.util.List;
/**
* Manages events which will be run in the future.
* Has its own thread since some events may need to be ran faster than the cycle time
* in the main thread.
*
* @author Graham
*
*/
public class EventManager implements Runnable {
/**
* A reference to the singleton;
*/
private static EventManager singleton = null;
/**
* A list of events that are being executed.
*/
private List<EventContainer> events;
/**
* Initialise the event manager.
*/
private EventManager() {
events = new ArrayList<EventContainer>();
}
/**
* The event manager thread. So we can interrupt it and end it nicely on shutdown.
*/
private Thread thread;
/**
* Gets the event manager singleton. If there is no singleton, the singleton is created.
* @return The event manager singleton.
*/
public static EventManager getSingleton() {
if(singleton == null) {
singleton = new EventManager();
singleton.thread = new Thread(singleton);
singleton.thread.start();
}
return singleton;
}
/**
* Initialises the event manager (if it needs to be).
*/
public static void initialise() {
getSingleton();
}
/**
* The waitFor variable is multiplied by this before the call to wait() is made.
* We do this because other events may be executed after waitFor is set (and take time).
* We may need to modify this depending on event count? Some proper tests need to be done.
*/
private static final double WAIT_FOR_FACTOR = 0.5;
@Override
/**
* Processes events. Works kinda like newer versions of cron.
*/
public synchronized void run() {
long waitFor = -1;
List<EventContainer> remove = new ArrayList<EventContainer>();
while(true) {
// reset wait time
waitFor = -1;
// process all events
for(EventContainer container : events) {
if(container.isRunning()) {
if((System.currentTimeMillis() - container.getLastRun()) >= container.getTick()) {
container.execute();
}
开发者_StackOverflow if(container.getTick() < waitFor || waitFor == -1) {
waitFor = container.getTick();
}
} else {
// add to remove list
remove.add(container);
}
}
// remove events that have completed
for(EventContainer container : remove) {
events.remove(container);
}
remove.clear();
// no events running
try {
if(waitFor == -1) {
wait(); // wait with no timeout
} else {
// an event is running, wait for that time or until a new event is added
int decimalWaitFor = (int)(Math.ceil(waitFor*WAIT_FOR_FACTOR));
wait(decimalWaitFor);
}
} catch(InterruptedException e) {
break; // stop running
}
}
}
/**
* Adds an event.
* @param event The event to add.
* @param tick The tick time.
*/
public synchronized void addEvent(Event event, int tick) {
events.add(new EventContainer(event,tick));
notify();
}
/**
* Shuts the event manager down.
*/
public void shutdown() {
this.thread.interrupt();
}
}</code></pre>
Ok, I see two problems:
Your events
List
is not synchronized and you are accessing it from different threads (one inEventManager
and second in the first piece of code withaddEvent()
).In this loop:
// process all events for(EventContainer container : events) { ... }
you are iterating over events List
and you cannot add new elements to it while iteration. I assume addEvent()
is adding new elements to this list, so basically you shouldn't call it during this iteration.
Both of this problems can be solved by using CopyOnWriteArrayList which enables safe access by concurrent threads and safely adding new elements during iteration (however new elements will be "visible" only in next iteration).
Solution:
private EventManager() {
events = new CopyOnWriteArrayList() ;
}
精彩评论