EventBus PerThreadQueuedDispatcher 和 ImmediateDispatcher 有什么区别?

2,885 阅读2分钟

问题

  1. PerThreadQueuedDispatcher.dispatch() 将事件和订阅者封装到一个 Event 对象中并将其提供给线程本地队列,然后轮询它以执行与ImmediateDispatcher.dispatch() 相同的逻辑有什么意义?
  2. dispatching.get() 总是返回 false 吗?为什么呢?

源码部分

ImmediateDispatcher#dispatch()

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

PerThreadQueuedDispatcher#dispatch()

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

假设条件

  1. 同一个线程中,执行过程中存在 事件 嵌套现象,具体为一个事件 A 触发了事件 B 和 C,而事件 B 又触发了事件 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");
    }
}

将这些事件视为一种树,其中每个事件都会产生额外的“子”事件:

    A
   / \
  B   C
 /
D

有两种常见的遍历树的方式:深度优先(A、B、D、C)和广度优先(A、B、C、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");
    }
}

我们可以将这些事件视为一种树,其中每个事件都会产生额外的“子”事件:

    A
   / \
  B   C
 /
D

有两种常见的遍历树的方式:深度优先(A、B、D、C)和广度优先(A、B、C、D)。这就是两个调度器之间的区别。

直接调度程序在事件创建时对其进行处理,从而导致深度优先调度。

执行步骤为: A->B->D->C

排队调度器在事件被提交时将它们排队,并通过轮询队列来处理它们,从而导致广度优先调度。该dispatching标志用于将队列处理限制为根事件。子事件将找到设置的标志并继续前进。

执行步骤为: A->B->C->D

总结

  1. ImmediateDispatcher 在事件处理上,属于深度优先调度
  2. PerThreadQueuedDispatcher 通过 dispatching 线程执行标示位和 queueForThread执行队列 ,在调度上属于广度优先调度

\