零:相关类UML图
一: Executor框架
public
Executor 是个简单的接口,它为灵活且强大的异步任务执行框架提供了基础,该框架能够支持多种不同类型的任务执行策略。它提供了一种标准的方法将任务的提交过程与执行过程解耦开来,并用 Runable 表示任务。
Executor 基于生产者 - 消费者模式,提交任务的模式相当于生产者(生成待完成的任务单元),执行任务的线程相当于消费者(执行完这些任务单元)。
1.1 Executor 的生命周期
Executor 的实现通常会创建线程来执行任务,但 JVM 只有在所有非守护线程全部终结后才会退出,因此,如果无法正确的关闭 Executor,那么 JVM 将无法结束。
由于 Executor 以异步的方式来执行任务,因此在任何时刻,之前提交任务的状态不是立即可见的,有的任务可能已经完成,有的可能正在运行,而其他的任务甚至可能在队列中等待执行。当关闭应用程序时,可能采用最平缓的关闭形式(完成所有已经启动的任务,并且不再接受新的任务),也可能采用最粗暴的关闭形式(直接关掉机房的电源),以及其他可能的形式。既然 Executor 是为应用程序提供服务的,不管是采用平缓或者粗暴的方式,他们也应该都是可关闭的,并将在关闭过程中受影响的任务的状态反馈给应用程序。
为了解决执行服务的生命周期的问题, 有了 Executor 的扩展接口 ExecutorService 接口, ExecutorService 接口添加了一些用于生命周期的方法,以及一些用于任务提交的便利方法。
public
ExecutorService 的生命周期有3中状态:运行、关闭和已终止。ExecutorService 在创建初期处于运行状态。shutdown 方法将执行平缓的关闭过程:不再接受 新的任务提交,同时等待已提交的任务执行完成,包含那些还未开始执行的任务。 shutdownNow 方法将执行粗暴的关闭过程:他将尝试取消所有运行中的任务,并将不再启动队列中尚未开始执行的任务。
在 ExecutorService 关闭后提交的任务将由“拒绝执行处理器(Rejected Exception Handler)”来处理(详见3.3节),他会抛弃任务,或者使得 execute 方法抛出一个未检查的 RejectedExecutionException。等所有任务都完成后, ExecutorService 将进入终止状态。
ExecutorService 接口与 Executor 相比,提供了返回 Future 对象,终止、关闭线程池的方法。Executor 接口定义的 execute() 方法只能接收 Runable 接口的对象,而 ExecutorService 接口中的 submit() 方法则可以接受 Runable 和 Callable 接口的对象。
1.2 Callable 和 Future
Executor 框架使用 Runable 作为其基本的任务表达形式。Runable 是一种有很大局限的抽象,虽然 run() 方法能够将相应的信息写入日志或者放入共享的数据结构,但他不能返回值或者抛出一个受检查的异常。
许多任务实际上都是存在延迟的计算 -- 执行数据库查询、从网络上获取资源。对于这些任务,Callable 是一种更好的抽象:它认为 call() 方法将返回一个值或者抛出一个异常。
ExecutorService 中的所有submit 方法都将返回一个Future,从而将一个Runable或者Callable提交给Executor,并得到一个Future用来获取任务的执行结果或者取消任务。Future 代表了一个异步运算的结果,它提供了判断运算是否完成、等待运算的进行以及获得运算结果等,该接口包含的方法如下所示:
public
其中,get 方法的行为取决于任务的状态(尚未开始、正在运行、已完成)。如果任务已完成,那么get会立即返回结果或者抛出一个 Exception ,如果任务没有完成