我使用Guava的EventBus来启动一些处理和报告结果.这是一个非常简单的可编译示例:
import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; public class Test { public static class InitiateProcessing { } public static class ProcessingStarted { } public static class ProcessingResults { } public static class ProcessingFinished { } public static EventBus bus = new EventBus(); @Subscribe public void receiveStartRequest(InitiateProcessing evt) { System.out.println("Got processing request - starting processing"); bus.post(new ProcessingStarted()); System.out.println("Generating results"); bus.post(new ProcessingResults()); System.out.println("Generating more results"); bus.post(new ProcessingResults()); bus.post(new ProcessingFinished()); } @Subscribe public void processingStarted(ProcessingStarted evt) { System.out.println("Processing has started"); } @Subscribe public void resultsReceived(ProcessingResults evt) { System.out.println("got results"); } @Subscribe public void processingComplete(ProcessingFinished evt) { System.out.println("Processing has completed"); } public static void main(String[] args) { Test t = new Test(); bus.register(t); bus.post(new InitiateProcessing()); } }
我使用这些事件作为其他软件组件做出反应准备进行此处理的一种方式.例如,它们可能必须在处理和恢复之前保存其当前状态.
我期望这个程序的输出是:
Got processing request - starting processing Processing has started Generating results got results Generating more results got results Processing has completed
相反,实际的输出是:
Got processing request - starting processing Generating results Generating more results Processing has started got results got results Processing has completed
应该指示处理开始的事件实际上是在实际处理之后发生的(“生成结果”).
看完源代码后,我明白为什么这样做.这是EventBus相关的source code.
/** * 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. */ void dispatchQueuedEvents() { // don't dispatch if we're already dispatching,that would allow reentrancy // and out-of-order events. Instead,leave the events to be dispatched // after the in-progress dispatch is complete. if (isDispatching.get()) { return; } // 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源中,一切都像我所期望的那样 – 所以真正的问题是我通过这样做引入了什么潜在的问题?设计师似乎认真地决定不允许重新入场.