Future的缺點
雖然Future可以異步的執行任務,但是還是有很多缺點:
沒有辦法回調
,需要手動的調用- 執行一組任務需要
等待所有的任務執行完
CompletionService簡介
CompletionService的實現目標是任務先完成可優先獲取到,即結果按照完成先後順序排序。
ExecutorCompletionService類,該類只有三個成員變量:
public class ExecutorCompletionService<V> implements CompletionService<V> {
private final Executor executor;
private final AbstractExecutorService aes;
private final BlockingQueue<Future<V>> completionQueue;
....
}
- 可以看到ExecutorCompletionService主要是增強executor線程池的。
- Task包裝後被塞入completionQueue,當Task結束,其Future就可以從completionQueue中獲取到。
執行流程爲:
基本使用
public class CompletionServiceTest {
public static void main(String[] args) {
Long start = System.currentTimeMillis();
//開啓3個線程
ExecutorService exs = Executors.newFixedThreadPool(5);
try {
int taskCount = 10;
// 結果集
List<Integer> list = new ArrayList<Integer>();
// 1.定義CompletionService
CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(exs);
// 2.添加任務
for(int i=0;i<taskCount;i++){
completionService.submit(new Task(i+1));
}
// 3.獲取結果
for(int i=0;i<taskCount;i++){
Integer result = completionService.take().get();
list.add(result);
}
System.out.println("list="+list);
} catch (Exception e) {
e.printStackTrace();
} finally {
//關閉線程池
exs.shutdown();
}
}
static class Task implements Callable<Integer> {
Integer i;
public Task(Integer i) {
super();
this.i=i;
}
@Override
public Integer call() throws Exception {
if(i==5) {
Thread.sleep(5000);
}else{
Thread.sleep(1000);
}
System.out.println("線程:"+Thread.currentThread().getName()+"任務i="+i+",執行完成!");
return i;
}
}
}
結果:
線程:pool-1-thread-1任務i=1,執行完成!
線程:pool-1-thread-2任務i=2,執行完成!
線程:pool-1-thread-3任務i=3,執行完成!
線程:pool-1-thread-4任務i=4,執行完成!
線程:pool-1-thread-1任務i=7,執行完成!
線程:pool-1-thread-3任務i=8,執行完成!
線程:pool-1-thread-4任務i=9,執行完成!
線程:pool-1-thread-2任務i=6,執行完成!
線程:pool-1-thread-1任務i=10,執行完成!
線程:pool-1-thread-5任務i=5,執行完成!
list=[1, 2, 3, 4, 7, 8, 9, 6, 10, 5]
- 可以發現結果順序就是任務完成的順序
阻塞和非阻塞獲取
public Future<V> take()throws InterruptedException
public Future<V> poll()
public Future<V> poll(long timeout,TimeUnit unit) throws InterruptedException
阻塞獲取
take方法回使調用者阻塞,可以保證一定會有Future取出
非阻塞獲取
poll方法會去查看是否有任務完成,有則取出;沒有,就會返回一個null