在EventBus
中有几种线程模式,这几种线程模式分别代表注册的方法可以运行在主线程,或者子线程,其中这几种线程模式之间的线程切换都是用HandlerPoster
,BackgroundPoster
,AsyncPoster
实现的,这里就来分析下它们的具体实现,看下别人的设计思想。
ThreadMode
是一个枚举类,每个实例都是一种线程状态,具体看下表的每个线程ThreadMode
作用
ThreadMode | mean |
---|---|
POSTING | 在那个线程post就在线程执行method |
MAIN | 在主线程执行method,可能会阻塞主线程 |
MAIN_ORDERED | 在主线程执行method,每次都将事件发送到队列,然后由handle发送执行 |
BACKGROUND | 在后台线程中执行,一个线程执行完之后才会去执行另外一个线程 |
ASYNC | 在后台线程中执行,每来一个线程执行一个,事件是并发的 |
在调用post
发送事件之后,都会走到postToSubscription
方法中,在这个方法中会根据threadMode
去区分该在什么情况下调用事件方法
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
//POSTING 直接去调用事件
case POSTING:
invokeSubscriber(subscription, event);
break;
//MAIN 先判断是否在主线程,在,就会直接调用,不过一般不建议在事件方法中执行过多的逻辑操作,否则会阻塞主线程
//否则通过mainThreadPoster.enqueue将事件发送给主线程执行方法,里面会有一个队列排队的过程,不会阻塞主线程
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
//mainThreadPoster默认不过null, 所以这种情况下会直接将事件发送给一个队列,然后依次取出,发送给主线程执行,这种情况下不会阻塞主线程
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
//内部通过一个线程池将事件发送给子线程执行,当有新的任务到来的时候,会存放到一个任务队列中,等待任务执行完之后,才会执行新任务
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
//内部通过一个线程池将事件发送给子线程执行,当有新的任务到来的时候,直接再开一个新线程
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
...
}
}
具体解释上面的注释已经解释清楚了,下面来看HandlerPoster
,BackgroundPoster
,AsyncPoster
在EventBus
中的使用。
它继承Handler实现Poster,可以看出内部是通过Handler将事件从子线程发送给主线程,当在子线程中时候,会通过调用enqueue
发送事件,看下其实现
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
//内部其实将其加到一个链表尾部上了
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) { //发送一个消息给主线程
throw new EventBusException("Could not send handler message");
}
}
}
}
在这段代码中首先通过PendingPost.obtainPendingPost(subscription, event)
获取一个PendingPost
,看下obtainPendingPost
的实现
static PendingPost obtainPendingPost(Subscription subscription, Object event) {
synchronized (pendingPostPool) {
int size = pendingPostPool.size();
if (size > 0) {
PendingPost pendingPost = pendingPostPool.remove(size - 1);
pendingPost.event = event;
pendingPost.subscription = subscription;
pendingPost.next = null;
return pendingPost;
}
}
return new PendingPost(event, subscription);
}
它首先会去检测pendingPostPool
中是否有数据,如果有,直接remove
,获取一个PendingPost
, 并将subscription
和event
赋值给pendingPost
的参数,如果pendingPostPool
中没有数据,直接去new一个PendingPost
回到HandlerPoster
的enqueue
方法,当获取到pendingPost
之后,会调用queue.enqueue(pendingPost)
,来看下enqueue
的实现
synchronized void enqueue(PendingPost pendingPost) {
if (pendingPost == null) {
throw new NullPointerException("null cannot be enqueued");
}
//链表数据接口,头部为head,下一次再进来tail.next指向pendingPost,tail向下移
if (tail != null) {
tail.next = pendingPost;
tail = pendingPost;
} else if (head == null) {
head = tail = pendingPost;
} else {
throw new IllegalStateException("Head present, but no tail");
}
notifyAll();
}
它的内部其实就是一个链表的数据结构,当第一次执行的时候, 直接将pendingPost
赋值给tail
和head
,下次再进来的时候,将值赋值给tail
的next
,然后让tail
指向新的值,这就是一个典型的链表数据结构。
回到HandlerPoster
的enqueue
方法,接下来会去调用sendMessage
,然后就会去回调handleMessage
, 在这个中去执行消息
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
//从队列中获取pendingPost
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
// 再次获取pendingPost,如果没有了,就没有消息了
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
//执行事件方法
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
它会从队列中获取一个pendingPost
,然后调用eventBus.invokeSubscriber
去执行事件方法,看下invokeSubscriber
的具体实现
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
//释放占用的资源
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}
最终会调用invokeSubscriber(subscription, event)
去执行事件方法,同时之前会调用releasePendingPost
释放pengingpost资源资源。到此这个HandlerPoster
发送事件到事件执行完流程也就分析完了。
它实现了Runnable
和Poster
两个接口,同时发送事件也是调用的enqueue
,看下其实现
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
也是将事件通过PendingPost
存到一个链表队列中,然后调用eventBus.getExecutorService().execute(this)
线程池执行这个异步任务,同时里面也有个executorRunning
变量来保证事件是顺序执行的。
EventBus的默认线程池是
Executors.newCachedThreadPool()
,当然也可以通过EventbusBuilder
传入我们自定义的线程池
看下run
方法的实现
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
run
方法里面也是通过循环取出队列中的任务执行,然后调用eventBus.invokeSubscriber(pendingPost)
去执行异步任务。
它也是实现Runnable
和Poster
两个接口,同时也是通过enqueue
发送事件,看下实现
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}
和BackgroundPoster
不同的是里面没有同步代码块,每次来一个任务都会调用执行,也就是说没执行一个任务都会开一个子线程
看下run
方法的实现
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
里面是每次调用run方法,只会执行一次queue.poll()
,然后调用eventBus.invokeSubscriber(pendingPost)
执行异步任务。
到此三个Poster
也就分析完了
1.
HandlerPoster
,BackgroundPoster
,AsyncPoster
三个Poster都是实现了Poster
接口,发送事件通过enqueue
发送
2.发送的事件是封装到PendingPost
中了,然后存到一个消息队列中
3.BackgroundPoster
里面封装的是一个Handler
,通过sendMessage
将事件从子线程发送给主线程
4.BackgroundPoster
里面是通过eventBus.getExecutorService().execute
执行异步任务,和AsyncPoster
不同的是,它执行完异步任务之后,才会去执行下一个任务。
5.AsyncPoster
里面是通过eventBus.getExecutorService().execute
执行异步任务,和BackgroundPoster不同的是,它每次发送一次事件,都会开一个子线程去执行异步任务。
看了EventBus的源码,其实难度不大,但是里面的设计思想还是很值得学习的,复习到了很多东西,注解,线程池,handler,反射,注解处理器等等,以后还是需要多读像这样比较经典的第三方库的源码的。