Почему я не получаю ConcurrentModificationException

У меня есть класс EventBus для добавления / удаления обработчика и отправки события обработчикам:

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

У меня есть AEventHandler, который слушает AEvent. Когда запускается AEvent, данный обработчик выполняет некоторые действия и удаляется из 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);
  }
}

В моем основном методе я создаю 2 обработчика, добавляю их в шину для прослушивания AEvent и запускаю событие AEvent:

  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 =-");
  }

Результат:

-= 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 =-

Метод отправки никогда не вызывается для второго обработчика. Это потому, что первый обработчик удаляет себя из шины (из handlersSublist) во время выполнения оператора цикла. Я решил эту проблему зацикливанием на копии handlersSublist, а не на самом handlersSublist. Но вопрос в том, почему я не получаю ConcurrentModificationException? Я изменяю ArrayList во время цикла. В этом потоке пользователь 1947415 получил ConcurrentModificationException, когда удалил первый элемент списка. В этом потоке пользователь 1699872 не получил исключения. потому что он использовал Iterator для цикла по списку. В чем дело? Почему я не получаю ConcurrentModificationException, поскольку я не использую Iterator и удаляю первый элемент списка?

Может кто-нибудь объяснить мне, почему?
Заранее спасибо,


person zatenzu    schedule 10.09.2015    source источник
comment
Я не вижу никакого цикла ... где цикл, который может вызвать исключение concurrentModificationException?   -  person Jkike    schedule 10.09.2015
comment
@Jkike В классе EventBus метод fireEvent.   -  person zatenzu    schedule 10.09.2015
comment
Вы имеете в виду, что отправка удаляет событие в fireEvent?   -  person learningloop    schedule 10.09.2015
comment
Но вы ничего не удаляете в этом цикле. Если я правильно прочитал, вы просто отправляете событие. Часть удаления не входит в цикл, позже вы обращаетесь к позиции объекта непосредственно в массиве, чтобы удалить его. Так что нет одновременного доступа   -  person Jkike    schedule 10.09.2015
comment
@Jkike Если я удалю вызов removeHandler() в методе onAEventReceived() класса AEventHandlerImpl1 и добавлю handlersSublist.remove (обработчик) в метод fireEvent() сразу после вызова event.dispatch (), я получу тот же результат, без исключения.   -  person zatenzu    schedule 10.09.2015