问题
PerThreadQueuedDispatcher.dispatch()
将事件和订阅者封装到一个 Event 对象中并将其提供给线程本地队列,然后轮询它以执行与ImmediateDispatcher.dispatch()
相同的逻辑有什么意义?- 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();
}
}
}
复制代码
假设条件
- 同一个线程中,执行过程中存在
事件
嵌套现象,具体为一个事件 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
总结
- ImmediateDispatcher 在事件处理上,属于深度优先调度
- PerThreadQueuedDispatcher 通过
dispatching
线程执行标示位和queueForThread
执行队列 ,在调度上属于广度优先调度
\