ExecutorCompletionService它专门为那些需要返回的结果的任务设计的,它内部维护了一个阻塞队列,当任务执行完毕后会把结果放到这个队列里,调用poll就可以获取到这些结果。当调用take方法的时候,如果队列中没有结果,会阻塞等待。
在之前介绍AbstractExecutorService类的invokeAny方法中提到了ExecutorCompletionService,invokeAny方法就是只有有一个结果就返回,用ExecutorCompletionService来实现再好不过了。
一、内部代码结构
从代码中可以看到,它实现了CompletionService接口,内部维护了Executor,以及阻塞队列CompletionQueue。默认的阻塞队列是LinkedBlockingQueue,也可以自定义。
public class ExecutorCompletionService<V> implements CompletionService<V> {
private final Executor executor;
private final AbstractExecutorService aes;
private final BlockingQueue<Future<V>> completionQueue;
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;
}
}
二、任务提交
从下面代码中的特殊之处在于QueueingFuture这个类,这个类里面有个done()方法,可以猜测这个方法就是任务执行完毕之后被调用的,调用的时候把结果放到阻塞队列中。后面我们从FutrueTask中去验证下我们的猜测
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;
}
private RunnableFuture<V> newTaskFor(Callable<V> task) {
if (aes == null)
return new FutureTask<V>(task);
else
return aes.newTaskFor(task);
}
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;
}
进入FutureTask类中寻找答案,其中run方法就是线程执行的入口,执行完毕之后会调用set()方法,一步步跟踪,我们找到了done()方法
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
// 这里就验证了我们的猜测,线程执行完之后确实调用了done()方法,会执行子类的逻辑
done();
callable = null; // to reduce footprint
}
三、结果获取
明白了结果是放在了阻塞队列,那么获取方法就简单了,直接调用队列的方法
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);
}