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.

3

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

Comments

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

         }
     }
  }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.