How severe is this bug?
Minor
How often can you reproduce this bug?
Always
Describe the bug
When attempting to unregister an event listener within an event handler method a ConcurrentModificationException is thrown.
Example code:
public class ConcurrentModificationTest implements EventListener {
private final UnregistrationEventTrigger unregistrationEventTrigger = new UnregistrationEventTrigger();
@Test
public void testEventRegistration() {
EventBus eventBus = EventBus.getDefault();
eventBus.register(unregistrationEventTrigger);
assertTrue(eventBus.isRegistered(unregistrationEventTrigger));
eventBus.fireEvent(new TestEvent());
assertFalse(eventBus.isRegistered(unregistrationEventTrigger));
}
public static class UnregistrationEventTrigger implements EventListener {
@EventHandler
public void fireUnregisterEvent(TestEvent event) {
EventBus.getDefault().unregister(this);
}
}
}
Provide the exception or error if any
java.lang.RuntimeException: An exception has occurred executing the method public void fireUnregisterEvent(dev.utano.eventbus.event.TestEvent)
Event: dev.utano.eventbus.event.TestEvent
at dev.utano.eventbus.EventBus.dispatchEvent(EventBus.java:152)
at dev.utano.eventbus.EventBus.fireEvent(EventBus.java:126)
at dev.utano.eventbus.ConcurrentModificationTest.testEventRegistration(ConcurrentModificationTest.java:19)
at java.lang.reflect.Method.invoke(Method.java:498)
at java.util.ArrayList.forEach(ArrayList.java:1259)
at java.util.ArrayList.forEach(ArrayList.java:1259)
Caused by: java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)
at java.util.ArrayList$Itr.next(ArrayList.java:861)
at dev.utano.eventbus.EventBus.dispatchEvent(EventBus.java:141)
... 5 more
What version of Java are you using?
JDK 1.8.0_281
What version of the EventBus are you using?
0.1
What operating system are you using and what version?
Windows 10 22H2
Provide the exact steps to reproduce this behaviour
Executing the provided test leads to a ConcurrentModificationException.
This occurs due to the internal iteration over the EventBus#listenerInstanceList ArrayList within the EventBus#dispatchEvent(Event) method, making it vulnerable to such exceptions.
Write here any additional information or context
Possible solutions
CopyOnWriteArrayList
Replacing the regular ArrayList with a CopyOnWriteArrayList can resolve the issue by ensuring that modifications to the list do not interfere with ongoing iterations.
Pros
- Guarantees thread safety during iteration.
- Resolves the ConcurrentModificationException issue by using a thread-safe collection.
Cons
- Adds overhead to adding or removing EventListeners due to creating a new copy of the underlying array.
- May impact performance, especially in scenarios with frequent add or remove operations.
Deferring unregistration of EventListeners
By implementing a queue system for EventListeners to defer their unregistration, modifications to the list occur only when safe to do so. This approach ensures that EventListeners are processed appropriately before looping through them in the EventBus#dispatchEvent(Event) method, thus resolving the issue of ConcurrentModificationException
Implementation
Introduces a queue mechanism for deferring unregistration of EventListeners.
Requires creating new classes to represent EventListeners or their instances.
Pros
- No overhead when registering and unregistering events
- Provides a clean separation of concerns between event handling and listener management.
Cons
- Requires a lengthier implementation process.
- May introduce additional complexity to the codebase.
How severe is this bug?
Minor
How often can you reproduce this bug?
Always
Describe the bug
When attempting to unregister an event listener within an event handler method a ConcurrentModificationException is thrown.
Example code:
Provide the exception or error if any
What version of Java are you using?
JDK 1.8.0_281
What version of the EventBus are you using?
0.1
What operating system are you using and what version?
Windows 10 22H2
Provide the exact steps to reproduce this behaviour
Write here any additional information or context
Possible solutions
CopyOnWriteArrayList
Replacing the regular
ArrayListwith aCopyOnWriteArrayListcan resolve the issue by ensuring that modifications to the list do not interfere with ongoing iterations.Pros
Cons
Deferring unregistration of EventListeners
By implementing a queue system for EventListeners to defer their unregistration, modifications to the list occur only when safe to do so. This approach ensures that EventListeners are processed appropriately before looping through them in the EventBus#dispatchEvent(Event) method, thus resolving the issue of ConcurrentModificationException
Implementation
Introduces a queue mechanism for deferring unregistration of EventListeners.
Requires creating new classes to represent EventListeners or their instances.
Pros
Cons