我正在使用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
。
/**
* 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事件类似,在所有处理程序完成之前调用事件不会返回。
我不太明白这个实现的原因。当然,事件保证按顺序排列,但周围代码的顺序完全失真。
有没有办法让总线按照描述运行并产生所需的输出?我确实读过Javadocs
EventBus保证它不会调用订阅者方法 多个线程同时,除非方法明确允许 它通过承载@AllowConcurrentEvents批注。
但我不认为这适用于此 - 我在单线程应用程序中看到了这个问题。
编辑
这里问题的原因是我 post
来自订户内部。由于事件总线不可重入,因此这些“子帖子”排队并在第一个处理程序完成后处理。我可以评论出来了 if (isDispatching.get()) { return; }
中的部分 EventBus
来源和一切都像我期望的那样 - 所以真正的问题是我通过这样做引入了哪些潜在的问题?似乎设计师做出了一个尽责的决定,不允许重入。