EventBus源码分析(四):线程模型分析(2.4版本)
来源:互联网 发布:龙芯支持windows 编辑:程序博客网 时间:2024/06/01 23:58
EventBus源码分析(一):入口函数提纲挈领(2.4版本)
EventBus源码分析(二):register方法保存事件的订阅者列表(2.4版本)
EventBus源码分析(三):post方法发布事件【获取事件的所有订阅者,反射调用订阅者事件处理方法】(2.4版本)
EventBus源码分析(四):线程模型分析(2.4版本)
EventBus源码解读详细注释(1)register的幕后黑手
EventBus源码解读详细注释(2)MainThread线程模型分析
EventBus源码解读详细注释(3)PostThread、MainThread、BackgroundThread、Async四种线程模式的区别
EventBus源码解读详细注释(4)register时刷新的两个map
EventBus源码解读详细注释(5)事件消息继承性分析 eventInheritance含义
EventBus源码解读详细注释(6)从事件发布到事件处理,究竟发生了什么!
EventBus有四种线程模型
- PostThread模式不需线程切换,直接在发布者线程进行事件处理。
- MainThread模式分类讨论:发布者线程是主线程则直接调用事件处理方法,否则通过Handler进行线程切换,切换到主线程处理事件,该模式下事件是串行执行的。
- BackgroundThread模式分类讨论:发布者线程不是主线程则在发布者线程直接处理事件,否则线程切换至线程池处理,所有该线程模式下的事件会在线程池中用一个线程排队串行处理(直到队列里边的事件处理完之后又有新的事件发布出来才会向线程池获取一个新的线程)。
- Async模式不关心发布者线程直接在线程池中开辟一个新的线程处理事件,和BackgroundThread模式不同的是,该线程模式的每个事件都是在线程池中开辟一个线程处理,事件之间并发处理,并不排队。
PendingPostQueue待处理事件队列
在分析线程模型之前,先看下各种线程模型都用到的数据结构PendingPostQueue,PendingPostQueue顾名思义是一个队列,对待处理事件进行了排队。
final class PendingPostQueue { private PendingPost head; private PendingPost tail; ...
PendingPostQueue维护了一个队列链表,队列的数据是PendingPost,PendingPost随后分析。
既然PendingPostQueue是一个队列,那么肯定提供了出队列和入队列的操作。
synchronized void enqueue(PendingPost pendingPost) { if (pendingPost == null) { throw new NullPointerException("null cannot be enqueued"); } 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(); }
可见入队列操作就是通过队尾指针操作将新数据插入队列尾部。如果队尾tail不为null,说明队列不空,将新数据作为新的队尾,修改队尾指针,如果队尾tail和队首head都是null,说明队列为空,将新数据同时设为队首和队尾。
最后通过notifyAll()释放对象锁,那么可以猜测如果队列为空出队列操作时会等待这把锁。
synchronized PendingPost poll() { PendingPost pendingPost = head; if (head != null) { head = head.next; if (head == null) { tail = null; } } return pendingPost; } synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException { if (head == null) { wait(maxMillisToWait); } return poll(); }
出队列操作就直接获取队列头head即可,队列为空时获取的head是null。此时如果调用的是poll(int maxMillisToWait)则会等待maxMillisToWait时长的锁,超时还没有获取锁,也就是读一个空队列超时了还没有入队列操作,则调用poll(),这时会返回null。
PendingPost:不变模式和对象池模式
PendingPostQueue维护了一个PendingPost类型数据的队列,那么PendingPost是什么呢?PendingPost是个对象池,通过静态ArrayList实现。同时PendingPost是一个最终类,被final修饰,语义角度意味着不可被继承,线程安全方面则表示该类绝对线程安全。
final class PendingPost { private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>(); Object event; Subscription subscription; PendingPost next; private PendingPost(Object event, Subscription subscription) { this.event = event; this.subscription = subscription; } 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); } static void releasePendingPost(PendingPost pendingPost) { pendingPost.event = null; pendingPost.subscription = null; pendingPost.next = null; synchronized (pendingPostPool) { // Don't let the pool grow indefinitely if (pendingPostPool.size() < 10000) { pendingPostPool.add(pendingPost); } } }}
既然是个对象池模式,那么必然提供了向对象池获取对象的方法和对象使用结束向对象池归还对象的方法。
PendingPost类通过将构造器设置为私有达到只能通过对象池获取PendingPost对象的目的。
obtainPendingPost从对象池获取对象,对象池中有保存的对象则从池子中获取对象(ArrayList尾部获取),没有保存线程的对象的话就通过new创建。
releasePendingPost则将使用后的对象归还给对象池,归还的时候要将对象的使用痕迹擦除,同时要限制对象池大小为10000,防止对象池无限增大。
MainThread线程模式:HandlerPoster
MainThread线程模式模式由HandlerPoster实现,通过Handler的线程切换功能做到在主线程中处理事件。从名字就知道HandlerPoster也是一个Handler,是Handler的子类。
final class HandlerPoster extends Handler { private final PendingPostQueue queue; private final int maxMillisInsideHandleMessage; private final EventBus eventBus; private boolean handlerActive; ...
queue是待处理事件队列
maxMillisInsideHandleMessage表示如果事件在maxMillisInsideHandleMessage时间内都没有处理完成的话就需要重新调度(重新处理rescheduled = true)。
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"); } } } }
enqueue从PendingPost的对象池获取一个PendingPost对象,设置subscription和event属性后就加入PendingPostQueue队列,如果主线程没有事件要处理,就发送一条空消息,激活handleMessage方法,在handleMessage方法里边对PendingPostQueue队列里边的所有事件反射调用事件处理方法。
@Override public void handleMessage(Message msg) { boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); while (true) { PendingPost pendingPost = queue.poll(); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized 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; } }
可知在handleMessage中时通过eventBus.invokeSubscriber(pendingPost)处理事件
void invokeSubscriber(PendingPost pendingPost) { Object event = pendingPost.event; Subscription subscription = pendingPost.subscription; PendingPost.releasePendingPost(pendingPost); if (subscription.active) { invokeSubscriber(subscription, event); } } void invokeSubscriber(Subscription subscription, Object event) { try { subscription.subscriberMethod.method.invoke(subscription.subscriber, event); } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); } }
invokeSubscriber方法取出PendingPost对象的event和subscription后先将PendingPost对象归还给线程池,然后反射调用事件处理方法。
MainThread线程模式总结:通过Handler从工作线程切换到主线程,在主线程中通过反射调用事件处理方法。
BackgroundThread线程模式:BackgroundPoster
BackgroundPoster继承自Runnable,某一时段内BackgroundThread模式的事件都会在BackgroundPoster的run方法中排队处理,也就是说该时段内的所有事件是在一个线程中排队后串行执行的(队列中的事件处理完之后又有新的事件发布才会新开线程)。
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); } } }
可以看到如果BackgroundPoster这个Runnable正在被线程池执行,这时候executorRunning==true,那么在executorRunning==true情况下发布的事件只会进队列,不会再次调用线程池的execute方法。这样的话在BackgroundPoster覆写的run方法中一定是通过死循环遍历处理队列中的事件,全部处理后才退出死循环,设置executorRunning=fasle,此后再发布事件才会在线程池中开辟一个新线程。
@Override 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) { Log.w("Event", Thread.currentThread().getName() + " was interruppted", e); } } finally { executorRunning = false; } }
Async线程模式:AsyncPoster
AsyncPoster同样也是一个Runnable,与Backgroundposter不同的是AsyncPoster并发度更高,不是在一个线程中对队列中的事件进行串行处理,而是每一个新添加的任务都会在线程池中开辟一个新线程执行。
public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); queue.enqueue(pendingPost); eventBus.getExecutorService().execute(this); } @Override public void run() { PendingPost pendingPost = queue.poll(); if(pendingPost == null) { throw new IllegalStateException("No pending post available"); } eventBus.invokeSubscriber(pendingPost); }
- EventBus源码分析(四):线程模型分析(2.4版本)
- EventBus源码解读详细注释(2)MainThread线程模型分析
- EventBus (二) 源码分析
- EventBus 2.4 源码分析
- EventBus源码分析(一):入口函数提纲挈领(2.4版本)
- EventBus源码分析(二):register方法保存事件的订阅者列表(2.4版本)
- Thrift源码分析(四)-- 方法调用模型分析
- Netty5源码分析(二) -- 线程模型分析
- EventBus源码分析(一):EventBus的使用
- EventBus(二)之源码分析
- EventBus源码分析(四): 发送Event和响应注册的回调方法
- Chrome源代码分析之进程和线程模型(四)
- Netty5源码分析(四) -- 事件分发模型
- ZMQ源码分析(二)-- 网络&线程模型
- Memcached源码分析(线程模型)
- Memcached源码分析(线程模型)
- Memcached源码分析(线程模型)
- Memcached源码分析(线程模型)
- Qt学习之路(11): MainWindow
- 学习SecureCRT
- [置顶] 优秀Android博客大全,整理了国内外大神博客/Github地址,是学习Android进阶的首选[转]
- Java项目中读取properties文件,以及六种获取路径的方法
- Java常用类库——数字格式化(NumberFormat)与大数操作(BigIntger、BigDecimal类)
- EventBus源码分析(四):线程模型分析(2.4版本)
- java基础之----文档制作
- 设计模式初探
- webApplicationContext 与servletContext详解
- php js rsa
- 第N次重装树莓派3:记录全过程
- CSS 高端进阶 - LESS
- Qt学习之路(12): 菜单和工具条
- APUE 1-3程序,列出一个目录中的所有文件