1

I have an EventBus class to add/remove handler and dispatch an event to handlers:

public class EventBus{
  private Map<Integer,List<EventHandler>> handlers = new HashMap<>();
  private static EventBus ourInstance = new EventBus();

  public static EventBus getInstance(){
    return ourInstance;
  }

  public <T extends EventHandler> void fireEvent(Event<T> event){
    int hash = event.getAssociatedType().hashCode();
    List<EventHandler> handlersSublist = handlers.get(hash);
    if(handlersSublist != null){
      System.out.println("I have " + handlersSublist.size() + " handlers for event " + hash); 
      for(EventHandler handler : handlersSublist){
        System.out.println("Fire event " + hash + " to " + handler.getClass().getName().toString());
        event.dispatch((T)handler);
      }
    }
  }

  public <T> void addHandler(Event.Type<T> type, EventHandler handler){
    Integer hash = type.hashCode();
    List<EventHandler> handlersSublist = handlers.get(hash);
    if(handlersSublist == null){
      handlersSublist = new ArrayList<>();
      handlers.put(hash,handlersSublist);
    }
    System.out.println("Add " + handler.getClass().getName().toString() + " for event " + hash);
    handlersSublist.add(handler);
  }

  public <T> void removeHandler(Event.Type<T> type, EventHandler handler) {
    Integer hash = type.hashCode();
    List<EventHandler> handlersSublist = handlers.get(hash);
    if (handlersSublist != null) {
      System.out.println("Remove " + handler.getClass().getName().toString() + " for event " + hash);
      handlersSublist.remove(handler);
    }
  }
}

I have an AEventHandler which listens to AEvent. When an AEvent is fired, a given handler does some stuff and removes itself from the eventBus:

public class AEventHandlerImpl1 implements AEventHandler
{
  @Override
  public void onAEventReceived(AEvent aEvent)
  {
    //do some stuff...
    //... and remove myself from the bus for AEvent
    EventBus.getInstance().removeHandler(AEvent.TYPE, this);
  }
}

In my main method, I create 2 handlers, I add them to the bus to listen to AEvent and I fire a AEvent event:

  public static void main(String[] args)
  {
    System.out.println("-= START =-");
    //create new handlers
    AEventHandlerImpl1 handler1 = new AEventHandlerImpl1();
    AEventHandlerImpl1 handler2 = new AEventHandlerImpl1();
    //add handlers on the eventBus
    EventBus.getInstance().addHandler(AEvent.TYPE, handler1);
    EventBus.getInstance().addHandler(AEvent.TYPE, handler2);
    //fire event
    EventBus.getInstance().fireEvent(new AEvent());
    //end
    System.out.println("-= END =-");
  }

The result is:

-= START =-
Add be.test.AEventHandlerImpl1 for event 1
Add be.test.AEventHandlerImpl1 for event 1
I have 2 handlers for event 1
Fire event 1 to be.test.AEventHandlerImpl1
Remove be.test.AEventHandlerImpl1 for event 1
-= END =-

The dispatch method is never called for second handler. It's because the first handler removes itself from the bus (from the handlersSublist) during the loop statement. I have solved this problem looping on a copy of handlersSublist, not on handlersSublist itself. But the question is, why don't I get a ConcurrentModificationException? I'm modifying an ArrayList during looping on it. In this thread, user1947415 got a ConcurrentModificationException when he removed the first element of the list. In this thread, user1699872 didn't get exception because he used an Iterator to loop on the list. What's going on? Why am I not getting a ConcurrentModificationException since I'm not using Iterator and I remove the first element of list?.

Can someone explain me why?
Thanks in advance,

Community
  • 1
  • 1
zatenzu
  • 347
  • 2
  • 10
  • I don't see any for cycle... where is the loop that sould throw the concurrentModificationException? – Jkike Sep 10 '15 at 12:25
  • @Jkike In the `EventBus` class, method `fireEvent`. – zatenzu Sep 10 '15 at 12:28
  • Do you mean the dispatch removes the event in `fireEvent`? – bprasanna Sep 10 '15 at 12:29
  • 1
    But you are not removing anything in that loop. If I read correct you are just dispatching the event. The remove part is not in a loop, later you are accessing the object position directly in the array to remove it. So no concurrent access – Jkike Sep 10 '15 at 12:30
  • @Jkike If I remove the call to `removeHandler()` in `onAEventReceived()` method of the `AEventHandlerImpl1` class and I add handlersSublist.remove(handler) in `fireEvent()` method just after the call to event.dispatch(), I get the same result, no exception. – zatenzu Sep 10 '15 at 12:57

0 Answers0