文章目录
概况
我们使用线程来异步执行任务。众所周知,Java线程的创建与销毁需要一定的开销,如果为每一个任务创建一个新线程来执行,势必将消耗大量的计算资源。 Java的线程既是工作单元,也是执行机制。
从JDK 5开始,把工作单元与执行机制分离开 来。工作单元包括Runnable和Callable,而执行机制由Executor框架提供。
Executor框架的两级调度模型
在HotSpot VM的线程模型中,Java线程(java.lang.Thread)被一对一映射为本地操作系统线程。Java线程启动时会创建一个本地操作系统线程;当该Java线程终止时,这个操作系统线程也会被回收。操作系统会调度所有线程并将它们分配给可用的CPU。
-
在上层,Java多线程程序通常把应用分解为若干个任务,然后使用用户级的调度器(Executor框架)将这些任务映射为固定数量的线程
-
在底层,操作系统内核将这些线程映射到硬件处理器上。
这种两级调度模型的示意图如下
从上图中可以看出,应用程序通过Executor框架控制上层的调度;而下层的调度由操作系统内核控制,下层的调度不受应用程序的控制。
Executor框架的3大组成部分
-
任务:包括被执行任务需要实现的接口:Runnable接口或Callable接口
-
任务的执行: 包括任务执行机制的核心接口
Executor
,以及继承自Executor的ExecutorService
接口。Executor框架有两个关键类实现了ExecutorService接口:ThreadPoolExecutor
和ScheduledThreadPoolExecutor
-
异步计算的结果: Future接口和实现Future接口的FutureTask类
Executor框架的主要接口和类
-
Executor:接口,它是Executor框架的基础,它将任务的提交与任务的执行分离开来。
-
ExecutorService:是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法
-
AbstractExecutorService:ExecutorService执行方法的默认实现
-
ScheduledExecutorService:一个可定时调度任务的接口
-
ScheduledThreadPoolExecutor:ScheduledExecutorService的实现,一个可定时调度任务的线程池
-
ThreadPoolExecutor:线程池的核心实现类,用来执行被提交的任务
Executor框架的使用示意图
主线程首先要创建实现Runnable或者Callable接口的任务对象。工具类Executors可以把一个Runnable对象封装为一个Callable对象(Executors.callable(Runnable task
)或Executors.callable(Runnable task,Object resule)
)
然后可以把Runnable对象直接交给ExecutorService执行(ExecutorService.execute(Runnable command)
);
或者也可以把Runnable对象或Callable对象提交给ExecutorService执行(ExecutorService.submit(Runnable task)
或ExecutorService.submit(Callable<T>task)
)
如果执行ExecutorService.submit(…)
,ExecutorService将返回一个实现Future接口的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
FixedThreadPool
创建使用固定线程数的线程池
FixedThreadPool适用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,它适用于负载比较重的服务器
使用示例: https://artisan.blog.csdn.net/article/details/77765659#newFixedThreadPool_412
SingleThreadExecutor
创建使用单个线程,SingleThreadExecutor适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。
使用示例:https://artisan.blog.csdn.net/article/details/77765659#newSingleThreadExecutor_524
CachedThreadPool
CachedThreadPool是大小无界的线程池,适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器。
使用示例:https://artisan.blog.csdn.net/article/details/77765659#newCachedThreadPool_625
ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor通常使用工厂类Executors来创建。Executors可以创建2种类型的ScheduledThreadPoolExecutor: ScheduledThreadPoolExecutor、SingleThreadScheduledExecutor
- ScheduledThreadPoolExecutor:
包含若干个线程的ScheduledThreadPoolExecutor - SingleThreadScheduledExecutor:只包含一个线程的ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而需要限制后台线程的数量的应用场景
使用示例:https://artisan.blog.csdn.net/article/details/77765659#newScheduledThreadPool_849
SingleThreadScheduledExecutor
SingleThreadScheduledExecutor适用于需要单个后台线程执行周期任务,同时需要保证顺序地执行各个任务的应用场景
使用示例:https://artisan.blog.csdn.net/article/details/77765659#newSingleThreadScheduledExecutor_761
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)
Runnable接口和Callable接口
Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor
或ScheduledThreadPoolExecutor
执行。它们之间的区别是Runnable不会返回结果,而Callable可以返回结果.