在介绍 EventBus 和 Spring 事件模型之前,有一道绕不过去的弯,那就是同步执行、异步执行的概念,以及在什么样的场景下使用同步、异步模型?
- 同步执行:所谓同步执行,指的就是在发出一个请求后,在没有获得调用结果之前,调用者就会等待在当前代码。直到获取到调用方法的执行结果,才算是结束。总结一句话就是 由调用者主动等待这个调用的结果,未返回之前不执行别的操作
- 异步执行:而异步执行恰恰相反,发出调用请求后立即返回,并向下执行代码。异步调用方法一般不会有返回结果,调用之后就可以执行别的操作,一般通过回调函数的方式通知调用者结果
这里给大家举个例子,能够很好的反应同步、异步的概念。比如说你想要给体检医院打电话预约体检,你说出自己想要预约的时间后,对面的小姐姐说:“稍等,我查一下时间是否可以”,这个时候如果你 不挂电话,等着小姐姐查完告诉你 之后才挂断电话,那这就是同步。如果她说稍等需要查一下,你告诉她:“我先挂了,查到结果后再打过来”,那这就是异步+回调
在我们上面写的示例代码上,毋庸置疑是通过同步的形式执行观察者模式,那是否可以通过异步的方式执行观察者行为?答案当然是可以。我们可以通过在 观察者模式行为执行前创建一个线程,那自然就是异步的。当然,不太建议你这么做,这样可能会牵扯出更多的问题。一起来看下 Guava 和 Spring 是如何封装观察者模式
Guava EventBus 解析
EventBus 是 Google Guava 提供的消息发布-订阅类库,是设计模式中的观察者模式(生产/消费者模型)的经典实现
具体代码已上传 GitHub 代码仓库,EventBus 实现中包含同步、异步两种方式,代码库中由同步方式实现观察者模式
因为 EventBus 并不是文章重点,所以这里只会对其原理进行探讨。首先 EventBus 是一个同步类库,如果需要使用异步的,那就创建时候指定 AsyncEventBus
- // 创建同步 EventBus
- EventBus eventBus = new EventBus();
- // 创建异步 AsyncEventBus
- EventBus eventBus = new AsyncEventBus(Executors.newFixedThreadPool(10));
注意一点,创建 AsyncEventBus 需要指定线程池,其内部并没有默认指定。当然也别像上面代码直接用 Executors 创建,作者是为了图省事,如果从规范而言,还是消停的使用默认线程池构建方法创建 new ThreadPoolExecutor(xxx);
EventBus 同步实现有一个比较有意思的点。观察者操作同步、异步行为时,均使用 Executor 去执行观察者内部代码,那如何保证 Executor 能同步执行呢。Guava 是这么做的:实现 Executor 接口,重写执行方法,调用 run 方法
- enum DirectExecutor implements Executor {
- INSTANCE;
- @Override
- public void execute(Runnable command) {
- command.run();
- }
- }
大家有兴趣可以去看下 EventBus 源码,不是很难理解,工作使用上还是挺方便的。只不过也有不好的地方,因为 EventBus 属于进程内操作,如果使用异步 AsyncEventBus 执行业务,存在丢失任务的可能