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的任務不會被執行。