并发编程-ExecutorCompletionService解析
1、简单介绍
我们在并发编程中,目前大部分做法都是将任务添加到线程池中,并拿到Future对象,将其添加到集合中,等所有任务都添加到线程池后,在通过遍历Future集合,调用future.get()来获取每个任务的结果,这样可以使得先添加到线程池的任务先等待其完成,但是并不能保证第一个添加到线程池的任务就是第一个执行完成的,所以会出现这种情况,后面添加到线程池的任务已经完成了,但是还必须要等待第一个任务执行完成并处理结果后才能处理接下来的任务。
如果想要不管添加到线程池的任务的顺序,先完成的任务先进行处理,那么就需要用到ExecutorCompletionService这个工具了。
2、源码解析
ExecutorCompletionService实现了CompletionService接口。CompletionService接种有有以下方法。
public interface CompletionService<V> {
// 提交任务
Future<V> submit(Callable<V> task);
// 提交任务
Future<V> submit(Runnable task, V result);
// 获取任务结果,带抛出异常
Future<V> take() throws InterruptedException;
// 获取任务结果
Future<V> poll();
// 获取任务结果,带超时
Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
}
可以看到接口中的方法非常简单,只有提交任务以及获取任务结果两类方法。
我们再看下实现类ExecutorCompletionService中的代码。
public class ExecutorCompletionService<V> implements CompletionService<V> {
private final Executor executor;
private final AbstractExecutorService aes;
private final BlockingQueue<Future<V>> completionQueue;
/**
* FutureTask的子类,重写FutureTask完成后的done方法
*/
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
// task任务执行完成后将任务放到队列中
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}
private RunnableFuture<V> newTaskFor(Callable