背景简介
在
Java
中,使用线程来异步执行任务。
Java
线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源。同时,为每一个任务创建一个新线程来执行,这种策略可能会使处于高负荷状态
的应用最终崩溃。
Java
的线程既是工作单元,也是执行机制。从
JDK 5
开始,把工作单元与执行机制分离开来。工作单元包括 Runnable
和
Callable
,而执行机制由
Executor
框架提供。
![](https://i-blog.csdnimg.cn/blog_migrate/db1035107992bfca72dcd66bfc89eaf3.png)
Executor 框架的结构与成员
Executor
框架主要由
3
大部分组成如下。
1.
任务。包括被执行任务需要实现的接口:
Runnable
接口或
Callable
接口。
2.
任务的执行。包括任务执行机制的核心接口
Executor
,以及继承自
Executor
的
ExecutorService
接口。
Executor
框架有两个关键类实现了
ExecutorService
接口(ThreadPoolExecutor
和
ScheduledThreadPoolExecutor
)。
3.
异步计算的结果。包括接口
Future
和实现
Future
接口的
FutureTask
类
下面是这些类和接口的简介
•
Executor
是一个接口,它是
Executor
框架的基础,它将任务的提交与任务的执行
分离开来。
•
ThreadPoolExecutor
是线程池的核心实现类,用来执行被提交的任务。
•
ScheduledThreadPoolExecutor
是一个实现类,可以在给定的延迟后运行命令,或
者定期执行命令。
ScheduledThreadPoolExecutor
比
Timer
更灵活,功能更强大。
•
Future
接口和实现
Future
接口的
FutureTask
类,代表异步计算的结果。
•
Runnable
接口和
Callable
接口的实现类,都可以被
ThreadPoolExecutor
或
Scheduled-ThreadPoolExecutor
执行
主线程首先要创建实现
Runnable
或者
Callable
接口的任务对象。工具类
Executors
可以把一个 Runnable
对象封装为一个
Callable
对象(
Executors.callable
(
Runnable task)
Executors.callable(
Runnable task
,
Object resule
))。
然后可以把 Runnable
对象直接交给
ExecutorService
执行(
ExecutorService.execute(Runnable command
));或者也可以把
Runnable
对象或
Callable
对象提交给ExecutorService 执行(
Executor-Service.submit
(
Runnable task
)或
ExecutorService.submit(Callable<T>task
))。
如果执行 ExecutorService.submit(
…
),
ExecutorService
将返回一个实现
Future
接口的对象(到目前为止的 JDK
中,返回的是
FutureTask
对象)。由于
FutureTask
实现了Runnable,程序员也可以创建
FutureTask
,然后直接交给 ExecutorService 执行。
最后,主线程可以执行 FutureTask.get()方法来等待任务执行完成。主线程也可以执行 FutureTask.cancel
(boolean mayInterruptIfRunning)来取消此任务的执行。
Executor 框架的成员
Executor 框架的主要成员:
ThreadPoolExecutor、 ScheduledThreadPoolExecutor、Future
接口、
Runnable
接口、
Callable
接口和
Executors。
(一) ThreadPoolExecutor
ThreadPoolExecutor
通常使用工厂类
Executors
来创建。
Executors
可以创建
3
种类型
的
ThreadPoolExecutor
:
SingleThreadExecutor
、
FixedThreadPool
和
CachedThreadPool
。
1. FixedThreadPool
。下面是
Executors
提供的,创建使用固定线程数的FixedThreadPool 的
API
。
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory
threadFactory)
FixedThreadPool
适用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,它适用于负载比较重的服务器。
2. SingleThreadExecutor
。下面是
Executors
提供的,创建使用单个线程的SingleThread-Executor 的
API
。
public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
SingleThreadExecutor
适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。
3. CachedThreadPool
。下面是
Executors
提供的,创建一个会根据需要创建新线程
的
CachedThreadPool
的
API
。
public static ExecutorService newCachedThreadPool()
public static ExecutorService newCachedThreadPool(ThreadFactorythreadFactory)
CachedThreadPool 是大小无界的线程池,适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器。
(二) ScheduledThreadPoolExecutor(定期执行命令)
ScheduledThreadPoolExecutor
通常使用工厂类
Executors
来创建。
Executors
可以创建2 种类型
的 ScheduledThreadPoolExecutor
,如下。
• ScheduledThreadPoolExecutor 。包含若干个线程 ScheduledThreadPoolExecutor 。• SingleThreadScheduledExecutor 。只包含一个线程 ScheduledThreadPoolExecutor 。
下面分别介绍这两种
ScheduledThreadPoolExecutor
。
下面是工厂类
Executors
提供的,创建固定个数线程的 ScheduledThreadPoolExecutor
的
API
。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize,
ThreadFactory threadFactory)
ScheduledThreadPoolExecutor
适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而需要限制后台线程的数量的应用场景。
下面是 Executors
提供的,创建单个线程的 SingleThreadScheduledExecutor
的
API
。
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory,threadFactory)
SingleThreadScheduledExecutor 适用于需要单个后台线程执行周期任务,同时需要保证顺序地执行各个任务的应用场景。
(
三
) Future
接口
Future
接口和实现
Future
接口的
FutureTask
类用来表示异步计算的结果。当我们把Runnable 接口或
Callable
接口的实现类提交(
submit
)给
ThreadPoolExecutor
或 ScheduledThreadPoolExecutor 时,
ThreadPoolExecutor
或
ScheduledThreadPoolExecutor
会
向我们返回一个
FutureTask
对象。下面是对应的
API
。
<T> Future<T> submit(Callable<T> task)
<T> Future<T> submit(Runnable task, T result)
Future<>
submit
(Runnable task)
有一点需要读者注意,到目前最新的
JDK 8
为止,
Java
通过上述
API
返回的是一个
FutureTask
对象。但从
API
可以看到,
Java
仅仅保证返回的是一个实现了
Future
接口的对象。在将来的 JDK
实现中,返回的可能不一定是
FutureTask