ExecutorCompletionService 通常与 ThreadPoolExecutor一起使用
ThreadPoolExecutor构造时可以带 BlockingQueue<Callable>初始化,称为workQueue;而ExecutorCompletionService 也可以带BlockingQueue<Future>初始化,称为completionQueue
几点认识
1. ExecutorService的 workQueue是控制任务提交的,如果workQueue满了,采用RejectedExecutionHandler的策略:有Abort, CallerRun 等等。submit任务时调用的是workQueue的offer方法,而不是put方法,所以并不会block caller。如果保证不丢任务,建议设置为CallerRunsPolicy,或采用http://stackoverflow.com/questions/2001086/how-to-make-threadpoolexecutors-submit-method-block-if-it-is-saturated的方案,自己重写RejectedExecutionHandler , 实现BlockPolicy。
2. ExecutorCompletionService的completionQueue是保存结果的,如果worker完成过多且completionQueue没有及时take, 导致满了,这时会抛出异常。相关代码细节参看ExecutorCompletionService.QueueingFuture.done()方法
import java.util.concurrent.*;
public class TestCompletionService {
public static void main(String[] args){
ExecutorService es = Executors.newFixedThreadPool(100);
ExecutorCompletionService ecs = new ExecutorCompletionService(es, new LinkedBlockingQueue(2));
for(int i=0; i<10; i++){
final int seq = i;
ecs.submit(new Callable(){
public Object call(){
System.out.println("thread executed" + seq);
return seq;
}
});
}
}
}
运行抛出异常
Exception in thread "pool-1-thread-2" java.lang.IllegalStateException: Queue full
at java.util.AbstractQueue.add(Unknown Source)
at java.util.concurrent.ExecutorCompletionService$QueueingFuture.done(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerSet(Unknown Source)
at java.util.concurrent.FutureTask.set(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)thread executed5
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
3. 调动ExecutorService.shutDown() 方法时,workQueue的任务仍会执行。但调用shutDownNow()时,workQueue的任务不会被执行。