Executor框架
Executor框架的两级模型
java的线程被一对一映射为本地操作系统的线程。
当java线程启动时,会创建一个本地操作系统的线程,当该java线程终止时,本地操作系统的进程也会被回收。
操作系统调度所有的线程并将他们分配给可用的CPU。
上层:java多线程程序将应用分解成多个任务,然后由用户级的调度器Executor框架将这些任务映射为固定数量的线程
下层:由操作系统的内核将这些线程映射到硬件处理器上。
Executor框架的结构
- 任务:包括被执行任务需要实现的接口:Runnable和Callable
- 执行:任务执行的核心接口Executor,以及继承自Executor的ExecutorService接口。Executor有两个关键类实现了ExecutorService接口:
- ThreadPoolExecutor线程池的核心实现类,用来执行提交的任务。
- ScheduledThreadPoolExecutor:可以在给定的延迟后运行命令,或者定期执行命令。
- 异步计算的结果:包含Future接口和实现了Future接口的FutureTask类。
Executor框架的执行过程:- 首先,主线程创建Runnable或者Callable接口的对象。(Executors工具类可以将Runnable对象封装成一个Callable对象:Executors.callable(Runnable task) 或者
Executors.callable(Runnable task, Object resule)) - 然后,将Runnable对象直接交给ExecutorService执行:ExecutorService.submit(Runnable command); 或者将Runnable或者Callable对象利用ExecutorService.submit(Runnable/Callable task)。
- 如果执行的是submit()方法,将返回一个实现了Future接口的对象或者FutureTask类。因为FutureTask类也实现了Runnable接口,因此也可以直接提交FutureTask去执行。
- 主线程可以调用FutureTask.get()来等待任务的执行,此方法会阻塞主线程;也可以调用FutureTask.cancel(boolean mayInterruptIfRunning)来取消任务的执行。
- 首先,主线程创建Runnable或者Callable接口的对象。(Executors工具类可以将Runnable对象封装成一个Callable对象:Executors.callable(Runnable task) 或者
Executor框架的成员
ThreadPoolExecutor
线程池,通常使用工厂类Executors创建。
- 单个线程的线程池:适用于需要保证线程的顺序执行,并且在任意时间不会有多个线程是活动的应用场景。
ExecutorService c = Executors.newSingleThreadExecutor(); - 固定数量的线程池,为了满足资源管理的需求,适用于负载比较重的服务器:
ExecutorService c = Executors.newFixedThreadPool(20); - 缓冲线程池:根据需要创建线程的无界的线程池。适用于执行很多的短期异步的小程序或者负载比较轻的服务器。
ExecutorService c = Executors.newCachedThreadPool();
ScheduledThreadPoolExecutor
继承自ThreadPoolExecutor,同时实现了ScheduledExecutorService接口。
ScheduledExecutorService接口定义了ScheduledThreadPoolExecutor能够延时执行任务和周期执行任务的功能;
Timer是单个后台线程的定时器,而ScheduledThreadPoolExecutor对应的是多个后台线程。
- 利用的DelayQueue(延迟阻塞无界队列)存储ScheduledFutureTask来实现的。
ScheduledFutureTask任务具有:定时时间、加入队列的序号以及任务的执行间隔周期等属性。
DelayQueue首先根据time排序,即时间早的任务在前面;如果时间相同,就根据加入队列的顺序即序号来排序。 - 使用Executors工具类来创建:
- 创建固定线程数的线程池:适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而控制后台线程的数量。
ExecutorService c = Executors.newScheduledThreadPool(20); - 创建单线程的线程池:需要单个线程后台执行周期任务,同时需要保证任务执行的顺序。
ExecutorService c = Executors.newSingleThreadScheduledExecutor();
- 创建固定线程数的线程池:适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而控制后台线程的数量。
Future接口
调用submit()方法返回的异步计算的结果:Future接口或者实现了Future接口的FutureTask类。
目前为止,异步处理结果返回的都是FutureTask类对象
- FutureTask类
- 实现了Runnable、Future接口
- 可以被Executor执行,也可以直接调用run()方法执行
- 基于AQS实现的,AQS是一个用来构建锁和其他同步组件的框架。提供通信机制用来原子性管理同步状态、阻塞和唤醒线程。
Runnable接口和Callable接口
Runnable接口不会返回结果,而Callable接口会返回结果。
但是可以利用工具类Executors将一个Runnable接口通过调用callable(Runnable task)封装成Callable接口。