executor执行框架是JDK1.5新增的,用于专注于任务执行的框架。其最大的特点就是将任务的创建和任务的执行分离,松耦合,已达到最大限度的利用计算机资源(线程和内存等)。在并发编程中,executor是一个必备的工具。
在分析源代码之前,首先需要对executor框架的整体结构有一定了解,以保证在进行源代码分析时,可以有很好的分析路线,不至于被绕晕。excutor框架最顶层是由四个部分构成:
1、ThreadFactory : 负责线程的创建,任务的执行是依靠线程完成的。
2、Executor : 负责线程的运行。
4、ThreadPoolExecutor : 负责对ThreadFactory创建的线程进行管理和调度。
3、Future : 获取任务的结果。因为任务是被放入线程中,启动线程进行异步执行。此时就需要一个对象来接收异步计算的结果(没有结果,也是一种特殊的结果)。Future就是用来接收这个返回结果的。这个结果可以是预期的结果,也可以是一个异常(Exception)。
一 、 ThreadFactory
ThreadFactory是一个接口,其中只有一个方法,即newThread(Runnable r)。从这个方法名字就可以知道,这接口是用来创建新的线程的。其使用也很简单,仅仅只需要实现newThread方法,根据自己的需要进行线程的创建即可。采用这种工厂方法的方式创建线程的优势在于,用户可以根据自己的需要进行线程的创建,同时用户也可以自定义线程工厂,比如保存线程创建线程的数量的ThreadFactory,创建特定优先级的线程的TrheadFacotry等等。
二、Executor
Executor也是一个接口,接口只有一个execute(Runnable command)方法。从发名字就可以知晓,这个方法是用于执行线程的。但是,Executor的定义过于单一,比如:当我们一次提交多个Runnable时,没有类似executorAny、executorAll这样的方法,用于执行任意Runnable和所有Runnable的方法。因此,Executor框架中提供了另外一个接口,即ExecutorService。ExecutorService是Executor的子接口。下面是ExecutorService中定义的方法:
void shutdown();
List shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
Future submit(Callable task);
Future submit(Runnable task, T result);
Future> submit(Runnable task);
List> invokeAll(Collection extends Callable> tasks)
List> invokeAll(Collection extends Callable> tasks,long timeout, TimeUnit unit)
T invokeAny(Collection extends Callable> tasks)
T invokeAny(Collection extends Callable> tasks, long timeout, TimeUnit unit)
ExecutorService扩展了Executor接口,定义各种各样的线程运行方式(invokeAny、 invokeAll等)。进行了这种分离之后,Executor和ExecutorService的各自的职责就很清晰了,更符合面向对象的编程思想。
三、ThreadPoolExecutor
ThreadPoolExecutor是一个类,其主要维护两个重要的资源:第一,线程(Thread);第二,任务(task)。因此,ThreadPoolExecutor 有两个很重要的属性: workers,workQueue。workers是一个HashSet
ThreadPoolExecutor主要用于解决两个问题:第一,优化性能,ThreadPoolExecutor采用线程池的方式实现,可以线程线程的数量,减少线程上下文的切换和计算资源的耗尽。此外,ThreadPoolExecutor的线程池可以重复利用线程,减少资源浪费,提升性能。第二,线程和资源的管理,ThreadPoolExecutor维护众多的属性,比如:已完成任务的数量、活跃的线程数量、任务拒绝策略、超时时间等等。
四、Future
Future用于获取任务的结果。因为任务是被放入线程中执行的,整个执行是异步的。因此,当任务运行完成后,需要一个对象来接收异步计算的结果(没有结果,也是一种特殊的结果)。Future就是用来接收这个返回结果的。这个结果可以是预期的结果,也可以是一个异常(Exception)。
综上所述,在Executor框架中,首先通过ThreadFactory创建线程;紧接着,通过ThreadPoolExecutor来管理ThreadFactory创建的线程和需要执行的任务;等到执行的时机成熟,则使用Executor来执行具体的任务;最后,通过Future对象来获取任务的执行结果。