vlambda博客
学习文章列表

异步编程之Future和Listener

众所周知计算机CPU资源宝贵,在实际场景中有很多任务要同步执行,但某些情况下同步需要一个线程等到另外一个线程,导致了CPU资源的浪费。实现同步任务高效执行的解决方案是变同步为异步。工程上通常使用future来实现达到异步效果,但通过调试future代码可以发现future.get获取结果时,调用着线程不得不等待被调用线程的执行结果,这是一种伪异步方法,无法实现真正的线程间异步效果。

先看一个案例:

假设main有两个主要的任务,1个任务firstjob比较耗时,交给子线程异步去做。还有一个anotherJob任务要等到firstjob任务执行完后和main传递的值都拿到才能执行。如何做到让调用者线程及时调用anotherJob任务呢?

首先我们通过future来实现,其中firstJob和anotherJob定义如下:


然后编写main函数实现任务调度

异步编程之Future和Listener


我们在13行代码异步执行firstJob任务;假设15行是主线程执行的其它任务,并将结果传递给anotherJob任务。在17行定义future.get去获取firstJob的执行结果,执行成功了便执行anotherJob。其中future.get是timeout获取结果,超过等待时间则报错。

该方法是异步的吗?

父子线程不一定是异步的。因为当父线程执行到future.get时,子线程不一定完成任务,父线程不得不等待。这时候会浪费父线程的时间。

如何更好的实现父子线程异步?

我们可以通过在父线程添加对子进程的监视器listener, 当子线程任务完成的时候自动执行监听器里面定义的内容。本案例是对firstJob添加监视器,当firstJob完成的时候自动执行anotherJob,这样父线程就不必再去检查子进程的完成状态,从而父子线程达到正在的异步。

定义listener:

异步编程之Future和Listener


定义具体的监听器ConcreteListener, 把anotherJob包装成函数任务。

异步编程之Future和Listener


定义jobExecutor去装载Listener。


主函数BossListener的25行定义doWork函数,把firstJob和JobExecutor关联起来,来实现当firstJob完成时自动执行anotherJob任务。


从上述代码可以看出,13行异步执行JobExecutor定义的firstJob任务,16行是给JobExecutor添加监视器,当firstJob完成以及15行的值计算完成后自动执行anotherJob任务,这样父线程就可以专注做自己的事情,来实现真正的父子线程异步执行。


扩展交流:

尝试调试netty源码,工程上Listener的源码实现是很复杂的,欢迎交