Executor 框架
Executor 框架
Java 的线程既是工作单元,也是执行机制。为了更好地管理和调度线程,Java 提供了强大的 Executor
框架。
Executor 框架的两级调度模型
在 Java 的 HotSpot VM
线程模型中,Java 线程(java.lang.Thread)
被一对一映射为本地操作系统线程。Java
线程启动时会创建一个本地操作系统线程。
- 上层调度:应用程序通常将应用分解为若干个任务,并使用用户级的调度器(
Executor
框架)将这些任务映射为固定数量的线程。 - 下层调度:操作系统内核将这些线程映射到硬件处理器上。应用程序通过
Executor
框架控制上层的调度,而下层的调度由操作系统内核控制,不受应用程序的直接控制。
Executor 框架的结构
- 任务:
- 任务的实现接口包括
Runnable
接口或Callable
接口。
- 任务的实现接口包括
- 任务的执行:
- 任务执行机制的核心接口是
Executor
,其继承接口为ExecutorService
。Executor
框架的两个关键实现类是ThreadPoolExecutor
和ScheduledThreadPoolExecutor
。
- 任务执行机制的核心接口是
- 异步计算的结果:
- 异步计算的结果由
Future
接口及其实现类FutureTask
表示。
- 异步计算的结果由
Executor 框架包含的主要类与接口
- Executor:
Executor
是一个接口,它是Executor
框架的基础,负责将任务的提交与任务的执行分离。
- ThreadPoolExecutor:
ThreadPoolExecutor
是线程池的核心实现类,用于执行提交的任务。
- ScheduledThreadPoolExecutor:
ScheduledThreadPoolExecutor
是一个实现类,可以在给定延迟后运行命令或定期执行命令,比Timer
更灵活,功能更强大。
- Future 接口与 FutureTask 类:
Future
接口及其实现类FutureTask
代表异步计算的结果。
- Runnable 接口与 Callable 接口:
- 这些接口的实现类都可以被
ThreadPoolExecutor
或ScheduledThreadPoolExecutor
执行。
- 这些接口的实现类都可以被
使用示意图
Executor 框架的工作流程
主线程首先创建实现
Runnable
或Callable
接口的任务对象。可以通过工具类Executors
将一个Runnable
对象封装为一个Callable
对象。然后将
Runnable
对象或Callable
对象提交给ExecutorService
执行。如果执行
ExecutorService.submit(...)
,ExecutorService
会返回一个实现Future
接口的对象(通常是
FutureTask
对象)。- 由于
FutureTask
实现了Runnable
,程序员也可以创建FutureTask
,然后直接交给ExecutorService
执行。
- 由于
主线程可以通过
FutureTask.get()
方法等待任务执行完成,或通过FutureTask.cancel(boolean mayInterruptIfRunning)
来取消任务的执行。
Executor 框架的成员
ThreadPoolExecutor
- SingleThreadExecutor:
- 创建一个使用单个线程的
ThreadPoolExecutor
。 - 适用于需要顺序执行各个任务,并且在任意时间点只有一个线程活动的场景。
- 使用无界队列
LinkedBlockingQueue
。
- 创建一个使用单个线程的
- FixedThreadPool:
- 创建一个使用固定线程数的
ThreadPoolExecutor
。 - 适用于为了资源管理而需要限制当前线程数量的场景,如负载较重的服务器。
- 使用无界队列
LinkedBlockingQueue
。
- 创建一个使用固定线程数的
- CachedThreadPool:
- 创建一个大小无界的线程池,适用于执行很多短期异步任务的小程序,或负载较轻的服务器。
- 使用无容量的
SynchronousQueue
作为线程池的工作队列。
ScheduledThreadPoolExecutor
- ScheduledThreadPoolExecutor:
- 包含多个线程的
ScheduledThreadPoolExecutor
,适用于需要多个后台线程执行周期任务,并且需要限制后台线程数量的场景。 - 使用
DelayQueue
作为任务队列。
- 包含多个线程的
- SingleThreadScheduledExecutor:
- 只包含一个线程的
ScheduledThreadPoolExecutor
,适用于需要单个后台线程执行周期任务,并且需要保证顺序执行任务的场景。
- 只包含一个线程的
Future 接口
Future
接口及其实现类FutureTask
用来表示异步计算的结果。FutureTask
根据其运行状态可以分为:- 未启动:
FutureTask.run()
方法尚未执行。 - 已启动:
FutureTask.run()
方法正在执行。 - 已完成:
FutureTask.run()
方法执行完毕并正常结束。
- 未启动:
- 当
FutureTask
处于未启动或已启动状态时,调用FutureTask.get()
方法将导致调用线程阻塞;当FutureTask
处于已完成状态时,调用FutureTask.get()
方法将立即返回结果或抛出异常。 FutureTask.cancel()
方法的行为:- 在未启动状态下,调用
FutureTask.cancel()
方法将导致任务永远不会被执行。 - 在已启动状态下,调用
FutureTask.cancel(true)
方法将中断执行任务的线程,调用FutureTask.cancel(false)
方法则不会影响正在执行的任务线程。 - 在已完成状态下,调用
FutureTask.cancel(...)
方法将返回false
。
- 在未启动状态下,调用
Runnable 接口 / Callable 接口
Runnable
接口不返回结果,而Callable
接口可以返回结果。- 可以通过工厂类
Executors
将一个Runnable
包装为一个Callable
。
Executors
Executors
是一个工具类,提供了便捷的方法来创建各种类型的线程池,例如 SingleThreadExecutor
、FixedThreadPool
和 CachedThreadPool
。这些方法简化了线程池的创建和管理,使得开发者可以轻松使用 Executor
框架处理并发任务。
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment