Java multithreading with Guava EventBus
I am using guava event bus. I have a server object that is supposed to be running all the time, listening for events to be sent to b us. So in junit test (MyObject is the class under test), I create it on my thread to simulate this and prevent blocking:
@Test
public void test() {
EventBus eventBus = new EventBus();
Thread thread= new Thread() {
@Override
public void run()
{
logger.debug("Creating new thread");
MyObject myObject = new MyObject(eventBus);
}
};
thread.start();
...
}
All is well, myObject is created on its Thread1. Then I send an event to the event bus in my test:
eventBus.post(triggerObject);
The weird thing I find is that all action / logging from my signed method inside the MyObject class is done again on the main thread. myObject is awaiting responses from some other parts, and this is blocking my test as it is on the main thread. Why is this happening? Am I doing something wrong with EventBus or Java streams?
source to share
Well, you are not doing anything on the created thread other than creating an object that finally ends up with a heap (which is shared between threads), but since a reference to it is not maintained after startup, it is also lost.
Your method @Subscribe
from myObject
is called on the same thread that it calls eventBus.post(event);
, not on the thread that it created myObject
.
The weird thing I find is that all action / logging from my signed method inside the MyObject class is done again on the main thread
If your class myObject
has a method @Subscribe
, then why does it need an EventBus instance inside the constructor? You probably want
MyObject myObject = new MyObject();
eventBus.register(myObject);`
instead MyObject myObject = new MyObject(eventBus);
source to share
This is what you are doing wrong with EventBus: when you dispatch an event to EventBus, the handlers for that thread are called on the same thread as the message.
In detail, what happens under the covers is that EventBus keeps a queue of handlers to execute in the queue ThreadLocal
. Until a thread needs a queue, it does not exist; when sending the first message, the ThreadLocalMap is initialized to empty empty, which is attached to the current thread. For this reason, the event queue is merged on the same thread that dispatches the events.
When multiple threads share an instance EventBus
, what is shared is the event handler registry - the same subscriber (s) instance will be invoked regardless of which thread is posting the event. But subscribers are called on the same thread as post ().
See Dispatcher.PerThreadQueuedDispatcher - this code probably doesn't match what you were using in 2014, but at the moment I think it's much more clear than trying to find the same functionality in the original implementation.
source to share