java – Guava EventBus调度

前端之家收集整理的这篇文章主要介绍了java – Guava EventBus调度前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我使用Guava的EventBus来启动一些处理和报告结果.这是一个非常简单的可编译示例:
  1. import com.google.common.eventbus.EventBus;
  2. import com.google.common.eventbus.Subscribe;
  3.  
  4. public class Test {
  5.  
  6. public static class InitiateProcessing { }
  7. public static class ProcessingStarted { }
  8. public static class ProcessingResults { }
  9. public static class ProcessingFinished { }
  10.  
  11. public static EventBus bus = new EventBus();
  12.  
  13. @Subscribe
  14. public void receiveStartRequest(InitiateProcessing evt) {
  15. System.out.println("Got processing request - starting processing");
  16. bus.post(new ProcessingStarted());
  17.  
  18. System.out.println("Generating results");
  19. bus.post(new ProcessingResults());
  20. System.out.println("Generating more results");
  21. bus.post(new ProcessingResults());
  22.  
  23. bus.post(new ProcessingFinished());
  24. }
  25.  
  26. @Subscribe
  27. public void processingStarted(ProcessingStarted evt) {
  28. System.out.println("Processing has started");
  29. }
  30.  
  31. @Subscribe
  32. public void resultsReceived(ProcessingResults evt) {
  33. System.out.println("got results");
  34. }
  35.  
  36. @Subscribe
  37. public void processingComplete(ProcessingFinished evt) {
  38. System.out.println("Processing has completed");
  39. }
  40.  
  41.  
  42. public static void main(String[] args) {
  43. Test t = new Test();
  44. bus.register(t);
  45. bus.post(new InitiateProcessing());
  46. }
  47. }

我使用这些事件作为其他软件组件做出反应准备进行此处理的一种方式.例如,它们可能必须在处理和恢复之前保存其当前状态.

我期望这个程序的输出是:

  1. Got processing request - starting processing
  2. Processing has started
  3. Generating results
  4. got results
  5. Generating more results
  6. got results
  7. Processing has completed

相反,实际的输出是:

  1. Got processing request - starting processing
  2. Generating results
  3. Generating more results
  4. Processing has started
  5. got results
  6. got results
  7. Processing has completed

应该指示处理开始的事件实际上是在实际处理之后发生的(“生成结果”).

看完源代码后,我明白为什么这样做.这是EventBus相关的source code.

  1. /**
  2. * Drain the queue of events to be dispatched. As the queue is being drained,* new events may be posted to the end of the queue.
  3. */
  4. void dispatchQueuedEvents() {
  5. // don't dispatch if we're already dispatching,that would allow reentrancy
  6. // and out-of-order events. Instead,leave the events to be dispatched
  7. // after the in-progress dispatch is complete.
  8. if (isDispatching.get()) {
  9. return;
  10. }
  11. // dispatch event (omitted)

发生了什么事情是因为我已经发布了顶级的InitiateProcessing事件,其余的事件就被推送到队列的末尾.我希望这样做类似于.NET事件,在所有处理程序完成之前,调用事件不会返回.

我不太明白这个实现的原因.当然,这些事件是有保证的,但周围的代码的顺序完全失真.

有没有办法让总线按照描述进行操作,并产生所需的输出?我在Javadoc中看过

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(isDispatching.get()){return; }部分在EventBus源中,一切都像我所期望的那样 – 所以真正的问题是我通过这样做引入了什么潜在的问题?设计师似乎认真地决定不允许重新入场.

解决方法

EventBus通常按照将事件发布到总线的代码不应该关心用户对事件做什么或者除了事件发布的顺序被尊重(在同步事件的情况下)的原则总而言之).

如果您希望在方法的特定时间调用特定方法,并且希望在方法继续之前确保这些方法已经完成(就像您在示例中),为什么不直接调用这些方法?当您使用事件总线时,您明确地将代码与正确发生的响应给定事件分开.这在许多情况下是可取的,并且是EventBus存在的主要原因,但它似乎并不完全相同.

猜你在找的Java相关文章