概述
在使用线程池批量提交task后,如果想要按照future完成的顺序依次处理future,可以通过ExecutorCompletionService实现以上场景。ExecutorCompletionService的实现原理是:
- 维护一个BlockingQueue<Future<V>>队列,在future完成后,将future添加到该队列中。ExecutorCompletionService默认使用LinkedBlockingQueue<Future<V>>队列,该队列具有FIFO特性,从而实现先完成的future先被处理。
- 基于代理模式,代理executor的execute()方法。
使用示例
void solve(Executor e,
Collection<Callable<Result>> solvers)
throws InterruptedException, ExecutionException {
CompletionService<Result> ecs
= new ExecutorCompletionService<Result>(e);
for (Callable<Result> s : solvers)
ecs.submit(s);
int n = solvers.size();
for (int i = 0; i < n; ++i) {
Result r = ecs.take().get();
if (r != null)
use(r);
}
}
成员变量
//被代理的executor
private final Executor executor;
private final AbstractExecutorService aes;
//记录已经完成的future的阻塞队列
private final BlockingQueue<Future<V>> completionQueue;
构造函数
/**
* Creates an ExecutorCompletionService using the supplied
* executor for base task execution and a
* {@link LinkedBlockingQueue} as a completion queue.
*
* @param executor the executor to use
* @throws NullPointerException if executor is {@code null}
*/
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>>();
}
QueueingFuture
QueueingFuture的作用是在future完成后,将之添加到queue中
/**
* FutureTask extension to enqueue upon completion
*/
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;
}
submit()方法
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
//代理executor的execute方法
executor.execute(new QueueingFuture(f));
return f;
}
private RunnableFuture<V> newTaskFor(Callable<V> task) {
if (aes == null)
return new FutureTask<V>(task);
else
return aes.newTaskFor(task);
}
take方法
public Future<V> take() throws InterruptedException {
//从阻塞队列中取出一个已经完成的future
return completionQueue.take();
}