6

我正在使用番石榴事件总线。我有一个类似服务器的对象,它应该一直在运行,监听要发布到 b us 的事件。所以在一个junit测试(MyObject是被测类)中,我在它自己的线程中创建它来模拟这个并防止阻塞:

  @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();
      ...
  }

一切都很好,myObject 是在它自己的线程 Thread1 中创建的。然后,我在测试中将事件发布到事件总线:

eventBus.post(triggerObject);

我发现的奇怪的事情是,我在 MyObject 类中订阅的方法中的所有操作/日志记录都再次在主线程中执行。myObject 等待来自某些其他部分的响应,这会阻止我的测试,因为它在主线程中。为什么会这样?EventBus 或 Java 线程是不是我做错了什么?

4

2 回答 2

7

好吧,除了创建一个最终在堆中结束的对象(在线程之间共享)之外,您在创建的线程中什么都不做,但是由于对它的引用在运行后不维护,所以它也会丢失。

您的@Subscribe方法 frommyObject在调用的同一线程中调用eventBus.post(event);,而不是在创建的线程中调用myObject

我发现的奇怪的事情是,我在 MyObject 类中的订阅方法中的所有操作/日志记录都再次在主线程中执行

如果您的MyObject类有一个@Subscribe方法,那么为什么它需要在构造函数中使用 EventBus 的实例?你可能想要

MyObject myObject = new MyObject();
eventBus.register(myObject);`

代替MyObject myObject = new MyObject(eventBus);

于 2014-08-18T20:41:11.830 回答
4

这是您对 EventBus 做错的事情:当您将事件发布到 EventBus 时,该线程的处理程序会在执行发布的同一线程中调用。

详细地说,在幕后发生的事情是 EventBus 正在存储要在队列中执行的处理程序ThreadLocal队列。在线程需要队列之前,它是不存在的;当您发布第一条消息时,ThreadLocalMap 会使用一个空队列进行初始化,该队列附加到正在运行的线程。因此,事件队列在发布事件的同一线程中耗尽。

当多个线程共享一个实例时EventBus,它们之间共享的是事件处理程序的注册表——无论哪个线程发布事件,都将调用订阅者的相同实例。但是订阅者在与 post() 相同的线程上被调用。

请参阅Dispatcher.PerThreadQueuedDispatcher - 该代码可能与您在 2014 年使用的不匹配,但目前我认为它比尝试在原始实现中找到相同的功能更容易理解。

于 2015-08-17T21:43:00.120 回答