Skip to content

Concurrent unregistration of events throws exception #2

@seba4316

Description

@seba4316

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions