第十章 Executor 框架
从 JDK 1.5 开始,Java 将工作单元与执行机制分离开来。
工作单元包括 Runnable 和 Callable,而执行机制由 Executor 框架提供。
10.1 Executor 框架介绍
10.1.1 Executor 框架的两级调度模型
上层:Java 多线程程序通常把应用分解为若干个任务,然后使用用户级的调度器(Executor 框架)将这些任务映射为固定数量的线程。
底层:操作系统内核将这些线程映射到硬件处理器上。
10.1.2 Executor 框架结构与成员
1. Executor 框架的结构
Executor 框架主要由 3 部分组成:
- 任务。包括被执行任务需要实现的接口:Runnable、Callable接口
- Runnable 接口和 Callable 接口 都可以被 ThreadPoolExecutor 或 ScheduledThreadPoolExecutor 执行
- 任务的执行。包括任务执行机制的核心接口 Executor,以及继承自 Executor 的 ExecutorService 接口。
- Executor ,是 Executor 框架的基础,将任务的提交与任务的执行分离开来
- ThreadPoolExecutor,是线程池的核心实现类,用来执行被提交的任务
- ScheduledThreadPoolExecutor,可以在给定的延迟后运行命令,或者定期执行命令,比 Timer 更灵活、强大。
- 异步计算的结果。包括接口 Future 和实现 Future 的 FutureTask 类
- Future 接口和实现 Future 的 FutureTask 类,代表异步计算的结果。
主要流程为:
- 主线程创建实现 Runnable、Callable 接口的任务对象
- Executors 将 Runnable 对象封装为 Callable 对象
- 将 Runnable 对象交给 ExecutorService.execute(Runnable command) 执行,或者交给 ExecutorService.submit(Callable
task) 执行 - 如果执行 submit,则 ExecutorService 返回一个实现 Future 接口的对象。
- 由于 FutureTask 实现了 Runnable,因此FutureTask 也可以直接交给 ExecutorService 执行
- 主线程执行 FutureTask.get() 方法等待任务执行完成;或者执行 FutureTask.cancel(boolean mayInterruptIfRunning) 来取消任务执行
2. Executor 框架的成员
- ThreadPoolExecutor:通常由工厂类 Executors 创建,可创建以下 3 种类型的ThreadPoolExecutor
- FixedThreadPool:创建使用固定线程数的ThreadPool,适用于需要限制当前线程数量的应用场景,适用于负载较重的服务器。
- SingleThreadExecutor:创建使用单个线程的 ThreadPool,适用于需要顺序执行各个任务;且在任意时间点,不会有多个线程是活动的应用场景
- CachedThreadPool:创建一个会根据需要创建新线程的 ThreadPool,是大小无界的线程池,适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器。
- ScheduledThreadPoolExecutor:通常由工厂类 Executors 创建,可创建以下 2 种类型的 ScheduledThreadPoolExecutor
- ScheduledThreadPoolExecutor,包含若干线程,适用于需要多个后台线程周期执行任务,同时需要限制后台线程数量的场景
- SingleThreadScheduledExecutor,只包含一个线程,适用于需要单个后台线程执行周期任务,同时需要保证顺序执行各个任务的应用场景
- Future/FutureTask:表示异步计算的结果
- Runnable/Callable:被 ThreadPoolExecutor 执行的任务。
- Runnable 不返回结果
- Callable 返回结果
10.2 ThreadPoolExecutor 详解
corePool:核心线程池的大小
maximumPool:最大线程池大小
BlockingQueue:阻塞队列,用来暂存任务的工作队列
RejectedExecutionHandler:拒绝策略,当 ThreadPoolExecutor 关闭或饱和时,将要调用的 Handler