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,