Executor(执行器)接口是执行框架最顶级的接口,定义了执行器的概念,并明确了该框架的核心目标:将任务的(创建)递交与执行分离(并负责执行)。Executor(执行器)接口的结构非常简单,其只有一个execute()方法,用于执行被递交来的任务。正是因为该方法的存在,开发者无需再自我实现繁复的执行流程(任务的执行并不似想象中简单,它需要在性能和资源之间相互权衡,并要兼容实际场景的各项制约,还要满足预期设想的卓越效果,因此是一件费心费力的事情,特别是如果这件事情还要做很多次的话…),而只需将任务创建并递交即可。任务的后续执行将彻底交由执行框架负责,对开发者而言完全屏蔽,从而达到了“将任务的(创建)递交与执行分离(并负责执行)”的目的。因此可以说正是由于execute()方法的存在,执行框架的作用才得以实现。
在实际开发中,我们推荐使用Executor(执行器)接口对象来代替使用显式创建线程的方式(这是最常见的任务执行方式,一般是为了获得更高的性能)来获取更好的任务执行效果,案例如下:
Executor executor = new Executor() {...}};
executor.execute(new RunnableTask());
executor.execute(new RunnableTask());
Executor(执行器)接口并不严格(即推荐但不强制)要求任务的执行是异步的。很多资料在讲述执行框架时,都会直接将之称呼为“线程池”来阐述(强调)其多线程及异步的特性,但这是完全错误的。之所以会有很多人将两者画上等号是因为在Executor(执行器)接口的所有实现中ThreadPoolExecutor(线程池执行器)类是最贴合实际开发场景且往往是能最快最好的获得收益的存在,使的众多开发者忽视(甚至是不知道)了其它实现而独尊“线程池”(网上虽然找篇文章基本都是讲线程池的,其它的绝口不言)。但上文已经提及过,执行框架的核心目标是“将任务的(创建)递交与执行分离(并负责执行)”,而对于任务的执行方式,则由各项子类自行实现,所谓的异步也只是众多执行方式的其中之一罢了。作为执行框架的最顶级,Executor(执行器)接口没有在任何方面强制在其子类在实现中只能使用异步的方式。因此请注意不要把执行框架与异步强绑定,两者之间不存在必然关系。但话虽如此,采用异步却依旧最推荐的实现方案,因为这样往往能获得最高的效益。
Executor(执行器)接口的同步实现方式案例如下:
public class DirectExecutor implements Executor {public void execute(Runnable r) {// 直接使用调用线程对任务进行处理。r.run();}}
Executor(执行器)接口虽然在执行框架中的拥有最高的地位,但由于其功能过于单一,因此在实际开发中往往会使用其子接口ExecutorService(执行器服务)代替。ExecutorService(执行器服务)是一个功能更加广泛的接口,在Executor(执行器)接口的基础上引入了关闭、终止及结果等概念,更加贴合实际的使用需求,关于该接口的具体内容会在其专项文章中阐述,此处不再提及。
Executor(执行器)接口是执行框架最顶级的接口,定义了执行器的概念,并明确了该框架的核心目标:将任务的(创建)递交与执行分离(并负责执行)。
/*** An object that executes submitted {@link Runnable} tasks. This interface provides a way of decoupling task submission from the* mechanics of how each task will be run, including details of thread use, scheduling, etc. An {@code Executor} is normally used* instead of explicitly creating threads. For example, rather than invoking {@code new Thread(new(RunnableTask())).start()} for* each of a set of tasks, you might use:* 一个执行提交的Runnable任务的对象。该接口提供了一种将任务提交与每个任务如何运行的机制分离的方法,包括线程使用、调度* 等细节。通常使用Executor来代替显式创建线程。例如,对于每一组任务,你可以使用以下方法,而不是调用{@code new Thread(new(RunnableTask())).start()}* * TODO 这是一段用于演示的伪代码,大意是使用一个Executor对象来执行Runnable任务,而不是显式的创建一个个的线程来执行。*
* Executor executor = anExecutor;* executor.execute(new RunnableTask1());* executor.execute(new RunnableTask2());* ...*
* * However, the {@code Executor} interface does not strictly require that execution be asynchronous. In the simplest case, an executor* can run the submitted task immediately in the caller's thread:* 然而,Executor接口并不严格要求执行是异步的。在最简单的情况下,执行器可以立即在调用者的线程中运行提交的任务:(执行器* 在定义上并不要求是异步的,其核心目标是为了复用已经存在的线程而避免显式的创建新线程)**
{@code* class DirectExecutor implements Executor {* public void execute(Runnable r) {* // 直接使用当前线程对任务进行处理。* r.run();* }* }}* * More typically, tasks are executed in some thread other than the caller's thread. The executor below spawns a new thread for each* task.* 更典型的,任务在调用者线程之外的线程中执行。下面的执行器为了每个任务生成一个新线程。**
{@code* class ThreadPerTaskExecutor implements Executor {* public void execute(Runnable r) {* // 新增一个新的线程执行。* new Thread(r).start();* }* }}* * Many {@code Executor} implementations impose some sort of limitation on how and when tasks are scheduled. The executor below* serializes the submission of tasks to a second executor, illustrating a composite executor.* 许多执行器实现对任务调度的方式和时间施加了某种限制。下面的执行器将任务的提交序列化到第二个执行器,演示了复合执行器。***
{@code* class SerialExecutor implements Executor {* // 数组双端队列,用于保存可执行任务。* final Queue tasks = new ArrayDeque();* // 执行器。* final Executor executor;* // 活动。* Runnable active;** SerialExecutor(Executor executor) {* // 传入一个可执行器。* this.executor = executor;* }** public synchronized void execute(final Runnable r) {* // 从队列中存入一个任务...但是为什么要用一个新的任务来承接旧的任务?* tasks.offer(new Runnable() {* public void run() {* try {* r.run();* } finally {* // 当任务具体被执行后,要继续执行下一个任务。* scheduleNext();* }* }* });* // 如果没有正在执行的任务,则作为起点触发整体的执行,应该只有第一个任务入队时会进行触发。* if (active == null) {* scheduleNext();* }* }** protected synchronized void scheduleNext() {* // 从队列中获取任务并使用真正有执行能力的执行器进行执行。SerialExecutor只是起对任务的管理作用。* if ((active = tasks.poll()) != null) {* executor.execute(active);* }* }* }} * * The {@code Executor} implementations provided in this package implement {@link ExecutorService}, which is a more extensive interface.* The {@link ThreadPoolExecutor} class provides an extensible thread pool implementation. The {@link Executors} class provides* convenient factory methods for these Executors.* 这个包中提供的Executor实现实现了ExecutorService,这是一个更广泛的接口。ThreadPoolExecutor类提供了一个可扩展的线程池实现。* Executors类为这些executor提供了方便的工厂方法(不推荐使用Executors来创建执行器实例,因为创建的执行器很消耗资源,数量多的* 情况下容易造成OOM,所以除非真的任务数量很庞大或者难以把握,否则还是推荐手动的创建执行器)。*
* Memory consistency effects: Actions in a thread prior to submitting a {@code Runnable} object to an {@code Executor}* happen-before* its execution begins, perhaps in another thread.* 内存一致性的影响:在向Executor提交Runnable对象之前,线程中的操作发生在它的执行开始之前,可能是在另一个线程中。(这一段不* 是特别懂,关于内存一致性本身和操作系统有关,暂时不管)** @author Doug Lea* @Description: 执行器接口* @since 1.5*/
public interface Executor {...
}
void execute(Runnable command) —— 执行 —— 虽然方法的名称是执行,但本质却是递交,递交后的任务将在未来的某个时间执行。
/*** Executes the given command at some time in the future. The command may execute in a new thread, in a pooled thread, or in the* calling thread, at the discretion of the {@code Executor} implementation.* 在未来的某个时间执行指定的命令。这个命令可能在一个新线程、一个池线程或者调用线程中执行,这取决于执行器的实现。** @param command the runnable task 可执行任务* @throws RejectedExecutionException if this task cannot be accepted for execution 如果这个任务无法被接受执行* @throws NullPointerException if command is null 如果命令为null*/
void execute(Runnable command);