Executor框架
在Java类库中, 任务执行的主要抽象不是Thread, 而是Executor.
- Executor为强大且灵活的异步任务执行框架提供了基础, 该框架能支持多种不同的任务执行策略
- 它提供了一种标准的方法将任务的提交过程与执行过程解耦开来, 并用Runnable来表示任务
- Executor的实现还提供了对生命周期的支持, 以及统计信息采集, 应用程序管理机制和性能监视等机制
线程池
- newFixedThreadPool: 固定长度的线程池
- newCachedThreadPool: 可缓存的线程池
- newSingleThreadExecutor: 单线程的Executor
- newScheduledThreadPool: 固定长度的线程池, 而且可以以定时或者延迟的方式来执行任务
Executor的生命周期
Executor扩展了ExecutorService接口以解决执行服务的生命周期问题
Executor的生命周期有3种状态:
- 运行: 初始状态
- 关闭:
- shutdown方法会执行平缓的关闭, 不接受新的任务, 同时等待已提交的任务执行完成-包括还没开始执行的任务
- shundownNow会执行粗暴的关闭, 尝试取消所有运行中的任务, 并不再启动队列中尚未开始的任务
- 在关闭后提交的任务将有拒绝执行处理器(Rejected Execution Handler)来处理
- 已终止
延迟任务与周期任务
Time类负责管理延迟任务以及周期任务, 但相比ScheduledThreadPoolExecutor有很多缺陷:
- Timer基于绝对时间调度, 因此对系统时钟敏感, 后者基于相对时间调度
- Timer执行所有定时任务时只会创建一个线程, 如果一个任务执行时间过长, 会破坏其他任务的定时精确性(“被延后的其他任务可能快速连续执行, 或者不执行”), 后者提供多个线程来执行任务
- Timer线程并不捕获异常, 抛出未受检异常线程直接挂掉不会恢复(线程泄漏)
如果要构建自己的调度服务, 可以使用DelayQueue
示例
ExecutorService
ExecutorService的所有submit()方法都将返回一个Future, 从而将一个Runnable或Callable提交给Executor来获得任务的执行结果或者取消任务, 还可以显式的为Runnable或Callable实例化一个FutureTask(FutureTask实现了Runnable, 也可以被提交给Executor)
CompletionService
CompletionService将Executor与BlockingQueue的功能融合到一起, 可以将Callable任务提交给它执行, 并通过take, poll等方法来获得已完成的结果, 而这些结果会在完成时被封装为Future
在实现上, ExecutorCompletionService在构造函数中创建一个BlockingQueue, 当提交任务时, 任务先被包装称为一个QueueingFuture.
为任务设定时限
Future.get方法可以设定超时时间, 超时将抛异常, 可以手动取消
Executor的invokeAll支持限时, 当所有任务被执行完毕, 或者调用线程被中断, 又或者超过指定时限时, InvokeAll将返回, 当超过指定时限后, 任何还未完成的任务都会取消