EventBus PerThreadQueuedDispat

问题

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

源码部分

ImmediateDispatcher#dispatch()

1
2
3
4
5
6
scss复制代码void dispatch(Object event, Iterator<Subscriber> subscribers) {
 checkNotNull(event);
 while (subscribers.hasNext()) {
   subscribers.next().dispatchEvent(event);
}
}

PerThreadQueuedDispatcher#dispatch()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
vbnet复制代码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

验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
typescript复制代码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");
  }
}

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

1
2
3
4
5
css复制代码    A
  / \
 B   C
/
D

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
typescript复制代码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");
  }
}

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

1
2
3
4
5
css复制代码    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执行队列 ,在调度上属于广度优先调度

\

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%