1

Yes I'm sure this question exist, but I have tried the answers and I guess I need a custom answer..

Anyway as the title suggest I'm getting a java.util.ConcurrentModificationException.

All this is called in it's own thread.

How I run the events :

private void setUpMainGameTimer() {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try{
                    TickEvent.call();
                } catch (Exception e){
                    e.printStackTrace();
                }
            }
        }, 0, gameSpeed);
    }

My stack trace.

java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at net.njar.rpg.Event.EventCaller.call(EventCaller.java:15)
    at net.njar.rpg.Event.TickEvent.call(TickEvent.java:10)
    at net.njay.rpg.Main.Main$1.run(Main.java:213)
    at java.util.TimerThread.mainLoop(Unknown Source)
    at java.util.TimerThread.run(Unknown Source)

Here is my EventCaller class.

public class EventCaller<Type extends Event> {

    @SuppressWarnings("unchecked")
    public void call(ArrayList<Listener> listeners, Event e){
        //Iterate through all of the listeners
        for (Listener h : listeners){

            //Iterate through each method
            for (Method m : h.getClass().getMethods()){
                //check if @EventHandler is present
                if (m.isAnnotationPresent(EventHandler.class)){
                    //get params
                    for (Class<?> param : m.getParameterTypes()){
                        //check if parameter is the same type as the passed event
                        if (param.equals(e.getClass())) {
                            try {
                                m.invoke(h, (Type) e);
                            } catch(Exception e1){
                                e1.printStackTrace();
                            }
                        }

                    }
                }
            }
        }
    }
}

And tick event:

public class TickEvent extends Event{
    private static long id = 0;

    public static void call(){
        id++;
        TickEvent e = new TickEvent();
        EventCaller<TickEvent> caller = new EventCaller<TickEvent>();
        caller.call(Event.getListeners(), e);
    }

     public long getTickID(){
         return TickEvent.id;
     }

     public static long getcurrentTickID(){
         return id;
     }
}

Event Class:

public class Event {

    private static ArrayList<Listener> listeners = new ArrayList<Listener>();

    public static void addListener(Listener listener){
        listeners.add(listener);
    }

    public synchronized static ArrayList<Listener> getListeners(){
        return Event.listeners;
    }

}

Just let me know what else you need.

Jordan Schnur
  • 1,225
  • 3
  • 15
  • 30
  • Where's the code for the method annotated with `@EventHandler`? – Bohemian Aug 28 '13 at 03:37
  • possible duplicate of [ConcurrentModificationException even with using Collections.sychronizedMap on a LinkedHashMap](http://stackoverflow.com/questions/18343989/concurrentmodificationexception-even-with-using-collections-sychronizedmap-on-a) – yshavit Aug 28 '13 at 04:39
  • I strongly suspect the thread is a red herring; is one of the callback modifying the `listeners` collection? – yshavit Aug 28 '13 at 04:43

2 Answers2

1

In EventCaller Class check your public void call(ArrayList<Listener> listeners, Event e) method.

Inside the for loop

for (Listener h : listeners){...}

h is getting modifier before the iteration is completed. Specifically check what does m.invoke(h, (Type) e); call does. It should not modify h.

Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
0

Answer 1: The list can be converted to an array with list.toArray() and iterate on the array. This approach is not recommended if the list is large.

Answer 2: The entire list can be locked while iterating by wrapping your code within a synchronized block. This approach adversely affects scalability of your application if it is highly concurrent.

Answer 3: JDK 1.5 gives you ConcurrentHashMap and CopyOnWriteArrayList classes, which provide much better scalability and the iterator returned by ConcurrentHashMap.iterator() will not throw ConcurrentModificationException while preserving thread-safety.

Answer 4: Remove the current object via the Iterator “it” which has a reference to the underlying collection “myStr”. The Iterator object provides it.remove() method for this purpose.

  public class EventCaller<Type extends Event> {

     @SuppressWarnings("unchecked")
     public void call(ArrayList<Listener> listeners, Event e){

         //Iterate through all of the listeners
         for(Iterator<Listener> iter = listeners.iterator(); iter.hasNext(); ) {
             Listener h = iter.next();

         }
     }
  }

}

Prabhakaran Ramaswamy
  • 25,706
  • 10
  • 57
  • 64