Executor框架

在Java类库中, 任务执行的主要抽象不是Thread, 而是Executor.
image.png

  • Executor为强大且灵活的异步任务执行框架提供了基础, 该框架能支持多种不同的任务执行策略
  • 它提供了一种标准的方法将任务的提交过程与执行过程解耦开来, 并用Runnable来表示任务
  • Executor的实现还提供了对生命周期的支持, 以及统计信息采集, 应用程序管理机制和性能监视等机制

线程池

  • newFixedThreadPool: 固定长度的线程池
  • newCachedThreadPool: 可缓存的线程池
  • newSingleThreadExecutor: 单线程的Executor
  • newScheduledThreadPool: 固定长度的线程池, 而且可以以定时或者延迟的方式来执行任务

Executor的生命周期

Executor扩展了ExecutorService接口以解决执行服务的生命周期问题
image.png

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.
image.png

image.png

为任务设定时限

Future.get方法可以设定超时时间, 超时将抛异常, 可以手动取消
image.png

Executor的invokeAll支持限时, 当所有任务被执行完毕, 或者调用线程被中断, 又或者超过指定时限时, InvokeAll将返回, 当超过指定时限后, 任何还未完成的任务都会取消
image.png