0

I'm working on a Java application which emits events which should be handled asynchronously, since the event handling is IO dependent and I want it to be decoupled from core logic.

I'm trying out Guava EventBus for this use case. In order to enable async event handling, I'm using AsyncEventBus with cached thread pool executor.

When multiple events are fired, the event listeners seem to be executed in sequential order, despite running on different threads.

Event generator class

public class MyEventEmitter {
    private static final Logger logger = LogManager.getLogger(MyEventEmitter.class);
    private EventBus eventBus;
    public MyEventEmitter(EventBus eventBus) {
        this.eventBus = eventBus;
    }
    public void emitEvent() {
        logger.info("[TEST] Emitting event");
        eventBus.post("String event");
        eventBus.post("String event");
        eventBus.post("String event");
        eventBus.post("String event");
    }
}

Event listener class


public class EventListener {

    private static final Logger logger = LogManager.getLogger(EventListener.class);
    private static int eventsHandled;
    private EventBus eventBus;
    public EventListener(EventBus eventBus) {
        this.eventBus = eventBus;
        this.eventBus.register(this);
    }

    @Subscribe
    public void stringEventDelayed(String event) throws InterruptedException{
        eventsHandled++;
        logger.info("[TEST] Async Event START " + event);
        Thread.sleep(1000);
        logger.info("[TEST] Async Event END " + event);

    }
}

EventBus setup

public class MainModule extends AbstractModule {

    @Override
    protected void configure() {
    }

    @Provides
    public EventListener getEventListener(EventBus eventBus){
        return new EventListener(eventBus);
    }

    @Singleton
    @Provides
    public EventBus getEventBus(){
        return new AsyncEventBus(Executors.newFixedThreadPool(4));
    }

    @Provides
    public MyEventEmitter getMyEventEmitter(EventBus eventBus){
        return new MyEventEmitter(eventBus);
    }
}

Here's what the output logs look like:

[INFO ] 2022-06-29 19:26:22.333 [main] EventListener - [TEST] EventListener setup
 [INFO ] 2022-06-29 19:26:22.345 [main] MyEventEmitter - [TEST] Emitting event
 [INFO ] 2022-06-29 19:26:22.346 [pool-2-thread-1] EventListener - [TEST] Async Event START String event
 [INFO ] 2022-06-29 19:26:23.348 [pool-2-thread-1] EventListener - [TEST] Async Event END String event
 [INFO ] 2022-06-29 19:26:23.348 [pool-2-thread-4] EventListener - [TEST] Async Event START String event
 [INFO ] 2022-06-29 19:26:24.353 [pool-2-thread-4] EventListener - [TEST] Async Event END String event
 [INFO ] 2022-06-29 19:26:24.359 [pool-2-thread-3] EventListener - [TEST] Async Event START String event
 [INFO ] 2022-06-29 19:26:25.361 [pool-2-thread-3] EventListener - [TEST] Async Event END String event
 [INFO ] 2022-06-29 19:26:25.361 [pool-2-thread-2] EventListener - [TEST] Async Event START String event
 [INFO ] 2022-06-29 19:26:26.364 [pool-2-thread-2] EventListener - [TEST] Async Event END String event

As can be seen above, all async listeners seem to be executed one after the other rather than concurrently.

I've tried changing Executor types, tried debugging locally, and tried searching but couldn't find anything specific to my issue.

1 Answers1

0

From the EventBus Javadocs:

The EventBus guarantees that it will not call a subscriber method from multiple threads simultaneously, unless the method explicitly allows it by bearing the AllowConcurrentEvents annotation. If this annotation is not present, subscriber methods need not worry about being reentrant, unless also called from outside the EventBus.

You should annotate your subscriber method with @AllowConcurrentEvents

Susurration
  • 135
  • 4