一:简介
public interface Executor {
void execute(Runnable command);
}
Executor是一个灵活而且强大的框架的基础,可以用于异步任务执行,而且支持很多不同类型的任务执行策略。它还为任务提交和任务执行之间的解耦提供了标准方法。为使用Runnable描述任务提供了通用的方式。Executor的实现提供了对生命周期的支持以及钩子函数,可以添加统计收集、应用程序管理机制和监视器等扩展。
Executor基于生产者-消费者模式。提交任务的执行者是生产者,执行任务的线程是消费者,使用Executor设计生产者-消费者模式最简单。
当你想为任务制定执行策略时,Executor更加灵活和适用。执行策略指明了:任务在什么线程中执行,以什么顺序执行(FIFO、LIFO、优先级),有多少任务并发执行,有多少个任务可以进入等待执行队列等等。
二:线程池
线程池管理一个工作者线程的同构池(就是一个池子里面放的是各个线程),它的优势是每次任务过来不用重新创建线程,直接从池子里获取,节省了一定得开销,合适大小的线程池能大大提高响应性。
Executors提供了多种类型线程池的创建。
public class Executors {
//创建定长的线程池 没提交一个任务就创建一个线程 直至到达最大值保持不变
//(一个线程由于非预期异常结束,会补充一条新的线程)
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
//创建一个可缓存的线程池 如果当前长度超过处理的需要时,可以灵活回收空闲线程,
//需求增加时,灵活添加新线程,不会对池子的长度做任何限制。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
//创建一个单线程的Executor,它只创建唯一的工作者线程来执行任务,如有异常会有另外一个线程替代
//它会保证依照任务队列规定的顺序执行。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
//创建一个定长线程池,支持定时的以及周期性的任务执行
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
}
三:Executors的生命周期
Executor实现通常只是为执行任务而创建线程,但JVM会在所有线程都终止后才退出,如果无法正确关闭Executor,将会阻止JVM的结束。因为Executor是异步地执行任务,所以在任何时间里,所有之前提交的任务的状态都是不能立即可见的。为了解决这个问题,ExecutorService扩展了Executor并且添加了一些用于生命周期管理的方法。
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
ExecutorService暗示生命周期的三种状态,运行,关闭,终止。ExecutorService创建后的初始状态是运行状态,shutdow方法会启用一个平缓的关闭过程:停止接收新线程,同时等待已经提交的任务完成(包括尚未执行的任务)。shutdowNow方法启用一个强制的关闭过程:尝试取消所有运行中的任务和在队列中尚未开始的任务。
在关闭后提交到ExecutorService中的任务,会被拒绝执行处理器处理(Rejected Execution Handler),拒绝执行处理器可能只是简单的放弃任务,也可能会引起executor抛出一个未检查的RejectedExecutionException。
四:可携带结果的任务:Callable和Future
Executor框架使用Runnable作为其任务的基本表达形式,Runnable不能返回一个值或者抛出受检查的异常。很多任务都会引起严重的计算延迟,对于这样的任务Callable是最佳的抽象,它在进入主进入点-call方法等待返回值,并为可能抛出的异常预先做好了准备。
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
Future描述了任务的生命周期,并提供了相关的方法来获取任务的结果,取消任务以及检验任务是否已经完成还是取消。如果任务没有完成,get会阻塞直到它完成。如果任务抛出异常,get方法会将异常封装成ExecutionException,然后重新抛出;如果任务取消,get方法会抛出CancellationException。
ExecutorService中所有的submit方法都返回一个Future,因此可以将Runnable或Callable提交给executor,然后得到一个Future,用它来重新获取任务执行的结果,或者取消任务。也可以显示为Runnable或Callable实例化一个FutureTask(FutureTask实现了Runnable,所以既可以将它交给Executor执行,又可以直接调用run方法运行)。
五:CompletionService
如果你向Executor提交了一个批处理任务,并且希望在他们完成后获得结果。这个时候可以使用完成服务(Completion Service),CompletionService整合了Executor和BlockingQueue的功能,你可以将Callable任务交给它执行,然后使用类似于队列中的take和poll方法,在结果完整可用时获得这个结果,
ExecutorCompletionService是CompletionService的一个实现,它在构造函数中创建一个BlockingQueue,用它保存完成的结果。计算完成会调用FutureTask中的done方法,当提交一个任务后,首先把这个任务包装为一个QueueingFuture,他是Future的一个子类,然后复写done方法,将结果置入BlockingQueue中。take和poll方法委托给了BlockingQueue,它会在结果不可用时阻塞。
public class ExecutorCompletionService<V> implements CompletionService<V> {
private final Executor executor;
private final AbstractExecutorService aes;
private final BlockingQueue<Future<V>> completionQueue;
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}
private RunnableFuture<V> newTaskFor(Callable<V> task) {
if (aes == null)
return new FutureTask<V>(task);
else
return aes.newTaskFor(task);
}
private RunnableFuture<V> newTaskFor(Runnable task, V result) {
if (aes == null)
return new FutureTask<V>(task, result);
else
return aes.newTaskFor(task, result);
}
public ExecutorCompletionService(Executor executor) {
if (executor == null)
throw new NullPointerException();
this.executor = executor;
this.aes = (executor instanceof AbstractExecutorService) ?
(AbstractExecutorService) executor : null;
this.completionQueue = new LinkedBlockingQueue<Future<V>>();
}
public ExecutorCompletionService(Executor executor,
BlockingQueue<Future<V>> completionQueue) {
if (executor == null || completionQueue == null)
throw new NullPointerException();
this.executor = executor;
this.aes = (executor instanceof AbstractExecutorService) ?
(AbstractExecutorService) executor : null;
this.completionQueue = completionQueue;
}
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
executor.execute(new QueueingFuture(f));
return f;
}
public Future<V> submit(Runnable task, V result) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task, result);
executor.execute(new QueueingFuture(f));
return f;
}
public Future<V> take() throws InterruptedException {
return completionQueue.take();
}
public Future<V> poll() {
return completionQueue.poll();
}
public Future<V> poll(long timeout, TimeUnit unit)
throws InterruptedException {
return completionQueue.poll(timeout, unit);
}
}
六:总结
围绕任务的执行来构造应用程序,可以简化开发,便于同步。Executor框架有助于你在任务的提交与任务的执行策略之间进行解耦,同时还支持很多不同类型的执行策略。