简体   繁体   中英

What's the difference between PerThreadQueuedDispatcher and ImmediateDispatcher in guava?

The dispatch() method of ImmediateDispatcher is:

void dispatch(Object event, Iterator<Subscriber> subscribers) {
  checkNotNull(event);
  while (subscribers.hasNext()) {
    subscribers.next().dispatchEvent(event);
  }
}

it just dispatch event to each subscrriber, so this is easy to understand.

However, the same method of PerThreadQueuedDispatcher is:

// both queue and dispatching are ThreadLocal.
@Override
void dispatch(Object event, Iterator<Subscriber> subscribers) {
  checkNotNull(event);
  checkNotNull(subscribers);
  Queue<Event> queueForThread = queue.get();
  queueForThread.offer(new Event(event, subscribers)); 
  // Isn't dispatching.get() always return false? Why the if then?
  if (!dispatching.get()) { 
    dispatching.set(true);
    try {
      Event nextEvent;
      while ((nextEvent = queueForThread.poll()) != null) {
        while (nextEvent.subscribers.hasNext()) {
          nextEvent.subscribers.next().dispatchEvent(nextEvent.event);
        }
      }
    } finally {
      dispatching.remove();
      queue.remove();
    }
  }
}

I have questions about this method:

  1. What's the point of encapsulating event and subscribers into an Event object and offer it to a threadlocal queue, and then poll it out to perform the same logic that ImmediateDispatcher.dispatch() does?
  2. Isn't dispatching.get() always return false? Why the if then?

The difference is when one event triggers another. Suppose we have an event A that triggers events B and C, and event B in turn triggers event D:

class Test {
    class A {}
    class B {}
    class C {}
    class D {}

    EventBus bus = new EventBus();

    Test() {
        bus.register(this);
        bus.post(new A());
    }

    @Subscribe void listen(A obj) {
        System.out.println("A");
        bus.post(new B());
        bus.post(new C());
    }

    @Subscribe void listen(B obj) {
        System.out.println("B");
        bus.post(new D());
    }

    @Subscribe void listen(C obj) {
        System.out.println("C");
    }

    @Subscribe void listen(D obj) {
        System.out.println("D");
    }
}

We can think of these events as a sort of tree, where each event spawns additional "child" events:

    A
   / \
  B   C
 /
D

There are two common ways of traversing a tree: depth-first (A, B, D, C) and breadth-first (A, B, C, D). That's the difference between the two dispatchers.

The immediate dispatcher processes events as they're created, resulting in depth-first dispatching. The queued dispatcher queues up events as they're submitted and processes them by polling the queue, resulting in breadth-first dispatching. The dispatching flag is used to restrict queue processing to the root event. Child events will find the flag set and move along.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM