Despacho do Guava EventBus

Estou usando o EventBus da Guava para iniciar alguns processamentos e relatar resultados. Aqui está um exemplo compilável muito simples:

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

Eu uso esses eventos como uma maneira de outros componentes de software reagirem em preparação para esse processamento. Por exemplo, eles podem ter que salvar seu estado atual antes do processamento e restaurá-lo depois.

Eu esperaria que a saída deste programa seja:

Got processing request - starting processing
Processing has started
Generating results
got results
Generating more results
got results
Processing has completed

Em vez disso, a saída real é:

Got processing request - starting processing
Generating results
Generating more results
Processing has started
got results
got results
Processing has completed

O evento que deve indicar que o processamento foi iniciado realmente ocorre após o processamento real ("geração de resultados").

Depois de analisar o código fonte, entendo por que ele está se comportando dessa maneira. Aqui está o relevanteCódigo fonte para oEventBus.

  /**
   * 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)

O que está acontecendo é que já estou despachando o nível superiorInitiateProcessing evento, o restante dos eventos é empurrado para o final da fila. Gostaria que isso se comportasse de maneira semelhante aos eventos do .NET, onde a invocação do evento não retornará até que todos os manipuladores tenham sido concluídos.

Não entendo bem o motivo dessa implementação. Certamente, os eventos são garantidos em ordem, mas a ordem do código ao redor fica completamente distorcida.

Existe alguma maneira de fazer o barramento se comportar conforme descrito e produzir a saída desejada? Eu li nos Javadocs que

O EventBus garante que ele não chamará um método de assinante de vários threads simultaneamente, a menos que o método permita explicitamente carregando a anotação @AllowConcurrentEvents.

Mas acho que isso não se aplica aqui - estou vendo esse problema em um único aplicativo encadeado.

Editar

A causa do problema aqui é que eu soupostde dentro de um assinante. Como o barramento de eventos não é reentrante, essas "sub-postagens" são colocadas na fila e são tratadas após a conclusão do primeiro manipulador. Posso comentar oif (isDispatching.get()) { return; } seção noEventBus fonte e tudo se comporta como eu esperaria - então a verdadeira questão é quais problemas potenciais eu apresentei ao fazer isso? Parece que os designers tomaram uma decisão consciente de não permitir a reentrada.

questionAnswers(4)

yourAnswerToTheQuestion