购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

4.4 Future任务的异步结果

Executor线程池框架由于是通过内部的线程池的线程来调度执行提交的任务,故任务是异步执行的。如果是不需要执行结果的任务,则在主线程直接返回即可。而有些任务是需要获取执行结果。例如,该任务是计算任务需要获取计算结果,故在Executor派生接口ExecutorService接口中定义了带返回结果的提交方法submit,方法返回值为Future接口的实现类对象。

Future接口的核心方法定义包括以下三种。

(1)异步获取任务执行结果的方法:get;

(2)取消任务执行的方法:cancel;

(3)获取任务执行状态的方法:isCancelled和isDone。

示例如下:

4.4.1 任务的执行结果FutureTask

Future接口的主要实现类为FutureTask, FutureTask类直接实现了RunnableFuture接口,通过RunnableFuture接口间接实现了Runnable和Future接口。故FutureTask的对象实例可以作为Runnable任务提交到Executor内部的线程池中去执行,然后通过自身来获取任务执行结果或者取消任务执行。代码如下:

FutureTask对象实例是被ThreadPoolExecutor内部的线程池的某个工作线程和阻塞等待获取结果的应用主线程所共享,故ThreadPoolExecutor内部线程池的工作线程在执行完这个任务后,可以通过FutureTask对象实例来通知和唤醒调用了get方法阻塞等待执行结果的应用主线程。同时应用主线程也可以取消该任务的执行,然后通过该FutureTask对象实例来通知工作线程。

在具体实现层面,线程池的工作线程和应用主线程之间是通过状态变量state来互相通知对方当前任务的执行状态。具体为工作线程在执行任务后,通过设置state为NORMAL表示成功执行,为EXCEPTIONAL表示执行异常。state状态枚举定义如下:

4.4.2 任务的提交与返回执行结果

在应用主线程中调用submit方法提交任务到Executor线程池框架内部的线程池,并调用异步结果封装类FutureTask的get方法阻塞获取任务执行结果。

在Executor线程池框架的内部实现中,创建或者调度线程池的一个空闲工作线程来执行该任务,在任务执行完成之后工作线程通知应用主线程。此时应用主线程从FutureTask对象实例的get方法返回,获取到任务的执行结果。如果应用主线程希望取消该任务的执行,则可以调用FutureTask对象实例的cancel方法。

1.提交任务到Executor线程池

ThreadPoolExecutor继承于抽象类AbstractExecutorService,在应用代码中调用ThreadPoolExecutor的对象实例的submit方法提交任务,对应AbstractExecutorService的submit方法实现如下:

创建一个FutureTask对象来包装应用定义的Runnable接口实现类task,调用execute方法将该对象交给内部的线程池去执行,最后返回该FutureTask对象引用给应用主线程。

2.应用主线程调用get等待执行结果

在FutureTask中的get方法实现如下:

分析:任务状态state小于等于COMPLETING表示任务还没开始执行或者正在执行,则应用主线程调用awaitDone阻塞休眠,等待Executor的工作线程执行任务并通知唤醒该应用主线程。awaitDone的方法实现如下:

在FutureTask内部维护了一个单向链表waiters,用于存放当前等待该任务执行结果的线程,在任务执行完成时,遍历该链表,唤醒每个等待线程。如下所示:

3.工作线程执行任务

工作线程执行该任务时,会调用该任务的run方法,即FutureTask的run方法。FutureTask的run方法定义如下:

分析:首先检查任务状态state是否为NEW,如果是,即还没执行过也没有被取消,则往下执行。执行完成之后,产生执行结果result,调用set方法来处理这个结果。

set方法的定义如下:将任务的执行结果赋值给FutureTask的成员变量outcome,更新任务执行状态state为NORMAL,最后调用finishCompletion通知所有等待这个任务执行结果的线程。如下所示:

finishCompletion的实现如下,遍历存放任务等待线程的链表,使用LockSupport.unpart唤醒对应的线程,然后将该等待线程从链表中移除。

最后回到FutureTask的get方法。应用主线程从awaitDone阻塞返回后,通过report方法来检测执行状态并返回任务执行结果。具体如下:

4.应用主线程取消任务

在应用主线程中,可以通过调用FutureTask的cancel方法在该任务执行之前,取消该任务的执行。

cancel方法主要是更新任务的状态state为INTERRUPTING或者CANCELLED,然后根据mayInterruptIfRunning来决定已经在执行的任务,是否中断对应的工作线程来中止该任务的执行。

最后调用finishCompletion方法来唤醒等待这个任务执行结果的线程,避免该任务被取消后,这些线程还在阻塞等待结果。具体定义如下:

对应到工作线程执行这个任务,在调用FutureTask的run方法时,先检查任务的状态state,如果发现不是NEW,即可能是CANCELLED、INTERRUPTING等,则直接返回,退出该任务的执行,从而与以上的cancel方法配合完成任务的取消。具体实现如下: mdXYPVudFCPUw1tuB2Chuher0HYCT41LDRG7DNzputpRhwDW64orQEiJ53slB6Z8

点击中间区域
呼出菜单
上一章
目录
下一章
×