I am using guava event bus. I have a server-like object that is supposed to be running all the time, listening for events to be posted to the b us. So in a junit test (MyObject is class under test), I create it in its own 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 good, myObject is created off in its own thread, Thread1. Then later, I post an event to the event bus in my test:
eventBus.post(triggerObject);
The weird thing I am finding is that all the actions/logging from my subscribed method inside of MyObject class are executing in the main thread again. myObject waits for responses from certain other parts, and this blocks my test since it's in the main thread. Why is this happening? Is it something I am doing wrong with the EventBus or Java threading?
Well you don't do nothing in the created thread except creating an object which finally ends up in heap (which is shared between threads), but since the reference to it is to not maintained after run, then it's also lost.
Your @Subscribe
method from myObject
is invoked in the same thread that calls eventBus.post(event);
and not in the thread that created myObject
.
The weird thing I am finding is that all the actions/logging from my subscribed method inside of MyObject class are executing in the main thread again
If your MyObject
class has an @Subscribe
method, then why does it need an instance of EventBus inside the constructor? You probably want
MyObject myObject = new MyObject();
eventBus.register(myObject);`
instead of MyObject myObject = new MyObject(eventBus);
It's something you are doing wrong with the EventBus: when you post an event to the EventBus, the handlers for that thread are called in the same thread that does the post.
In detail, what's happening under the covers is that EventBus is storing the queue of handlers to execute in a ThreadLocal
queue. Until a thread needs the queue, it doesn't exist; when you post the first message, the ThreadLocalMap is initialized with an empty queue which is attached to the running thread. For this reason, the queue of events is drained in the same thread that posts the events.
When multiple threads share an instance of an EventBus
, what's shared between them is the registry of event handlers -- the same instance(s) of the subscriber(s) will be called no matter which thread posts the event. But the subscribers get called on the same thread as the post().
See Dispatcher.PerThreadQueuedDispatcher -- that code probably doesn't match what you were using in 2014, but at the moment I think it's a lot more comprehensible than trying to find the same functionality in the original implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With