注意:所有文章除特别说明外,转载请注明出处.
[TOC]
第十章 Executor框架
Java的线程既是工作单元,也是执行机制。所以在JDK 1.5 之后将工作单元和执行机制分离开,工作单元包括 Runnable 和 Callable ,执行机制由 Executor 框架提供。
Executor 管理多个异步任务的执行,而无需程序员显式地管理线程的生命周期。这里的异步是指多个任务的执行互不干扰,不需要进行同步操作。
10.1 Executor 框架简介
10.1.1 Executor 框架的两级调度模型
在上层,Java多线程程序通常将应用分解为若干个任务,然后使用用户级的调度器(Executor框架)将这些任务映射为固定数量的线程。
在底层,操作系统内核将这些线程映射到硬件处理器上。
10.1.2 Executor 框架的结构和成员
1.Executor 框架的结构
注意:Executor框架由两个关键类实现了ExecutorService接口(ThreadPoolExecutor和ScheduledThreadPoolExecutor)。
Executor 框架由3大部分组成:
1.任务:包括被执行任务需要实现的接口(Runnable接口 | Callable接口)
2.任务的执行:包括任务执行机制的核心接口Executor,以及继承Executor的ExecutorService接口。
3.异步计算的结果:包括接口Future接口和实现Future接口的FutureTask类。
Executor框架包括的主要的类和接口:
1.Executor接口:是Executor框架基础,将任务的提交与任务的执行分离开。
2.ThreadPoolExecutor线程池核心实现类:用来执行被提交的任务。
3.ScheduledThreadPoolExecutor实现类:在给定的延迟后运行命令,或者定期执行命令。
4.Future接口和实现Future接口的FutureTask类:代表异步计算的结果。
5.Runnable接口和Callable接口的实现类:可以被ThreadPoolExecutor或Scheduled-ThreadPoolExecutor执行。
任务执行过程:
1.首先主线程创建实现 Runnable 或者 Callable 接口的任务对象。工具类Executor可将一个Runnable对象封装成一个Callable对象。
2.然后可以将Runnable对象直接交给ExecutorService执行(ExecutorService.execute(Runnable command)),或者可以将Runnable对象交给 ExecutorService执行(ExecutorService.submit(Runnable task))或ExecutorService.submit(Callable
3.最后主线程可以执行 FutureTask.get() 方法来等待任务执行完成。主线程也可以执行 FutureTask.cancel() 来取消任务执行。
2.Executor框架成员
1.ThreadPoolExecutor
ThreadPoolExecutor 通常使用工厂类Executors来创建。Executors可以创建3种类型的ThreadPoolExecutor。
1.FixedThreadPool
2.SingleThreadExecutor
3.CachedThreadPool
2.ScheduledThreadPoolExecutor
1.ScheduledThreadPoolExecutor:适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而需要限制后台线程的数量的应用场景。
2.SingleThreadScheduledExecutor:适用于需要单个后台线程执行周期任务,同时需要保证顺序执行各个任务的应用场景。
3.Future接口
Future接口和实现Future接口的FutureTask类用来表示异步计算的结果。当把Runnable接口或Callable接口的实现类提交(submit)给ThreadPoolExecutor或ScheduledThreadPoolExecutor时,ThreadPoolExecutor或ScheduleThreadPoolExecutor会向我们返回一个FutureTask对象。
4.Runnable接口和Callable接口
Runnable接口和Callable接口都可以被ThreadPoolExecutor | ScheduledThreadPoolExecutor 执行,它们之间的区别在于 Runnable 不会返回结果,而Callable可以返回结果。
10.2 ThreadPoolExecutor详解
主要有是三种Executor:1.CachedThreadPool:一个任务创建一个线程。2.FixedThreadPool:所有任务只能使用固定大小的线程。3.SingleThreadExecutor:相当于大小为 1 的 FixedThreadPool。
10.2.1 FixedThreadPool详解
该线程池被称作可重用固定线程数线程池。
10.2.2 SingleThreadExecutor详解
该线程池是使用单个worker线程的Executor。
10.2.3 CachedThreadPool详解
该线程池是一个会根据需要创建新线程的线程池。
10.3 ScheduledThreadPoolExecutor详解
ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutorz。其主要用来在给定的延迟之后运行任务,或者定期执行任务。其功能与Timer类似,但ScheduledThreadPoolExecutor功能更强大、灵活。Timer对应单个后台线程。
10.3.1 ScheduledThreadPoolExecutor 的运行机制
10.4 FutureTask详解
Future接口和实现了Future接口的FutureTask类,表示的是异步计算的结果。
10.4.1 FutureTask简介
FutureTask除实现Future接口之外,还是Runnable接口。所以FutureTask可以交给Executor执行,也可以调用线程直接执行(FutureTask.run())。
FutureTask可以处于以下3中状态:
1.未启动:
2.已启动:
3.已完成:
10.4.2 FutureTask的使用
可以将FutureTask交给Executor执行,或者通过ExecutorService.submit()方法返回一个FutureTask,然后执行FutureTask.get()方法或FutureTask.cancel()方法。
10.4.3 FutureTask的实现
FutureTask的实现基于 AbstractQueuedSynchronizer(AQS)。
提示:java.util.concurrent中很多阻塞类(ReentrantLock)都是基于AQS实现的。AQS 是一个同步框架,它提供通用机制来原子性管理同步状态、阻塞和唤醒线程,以及维护被阻塞线程的队列。
提示:基于AQS实现的同步器包括:ReentrantLock | Semaphore | ReentrantReadWriteLock | CountDownLatch | FutureTask。
每一个AQS实现的同步器都会包含两种类型的操作:
1.至少有一个acquire操作。该做操阻塞调用线程,直到AQS允许这个线程执行。
FutureTask的acquire操作是:get()/get(long timeout, TimeUnit unit)方法调用
2.至少有一个release操作。该操作改变AQS的状态,改变后的状态可允许一个或多个阻塞线程被解除阻塞。
FutureTask的release操作包括run()方法和cancel()方法
10.5 Future 模式
Future模式是多线程开发中常见的一种设计模式,核心思想是异步调用。在调用的方法返回的结果很慢的时候,我们可以让它在后台慢慢执行,我们利用这段时间处理其它任务,在真正需要数据的场合再去尝试获得需要的数据。
10.5.1 Future模式主要方法
1. boolean cancel(boolean mayInterruptIfRunning);//取消任务
2. boolean isCancelled();//是否已经取消
3. boolean isDone();//是否已经完成
4. V get() throws InterruptedException..;//取得返回对象
5. V get(long timeout, TimeUnit unit);//取得返回对象,可以设置超时时间