當向線程池提交callable任務後,我們可能需要一次性獲取所有返回結果,有三種處理方法。
方法一:自己維護返回結果
// 創建一個線程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 存儲執行結果的List
List<Future<String>> results = new ArrayList<Future<String>>();
// 提交10個任務
for ( int i=0; i<10; i++ ) {
final int tmp = i;
Future<String> result = executorService.submit( new Callable<String>(){
public String call(){
int sleepTime = new Random().nextInt(1000);
Thread.sleep(sleepTime);
return "線程"+tmp+"睡了"+sleepTime+"秒";
}
} );
// 將執行結果存入results中
results.add( result );
}
// 獲取10個任務的返回結果
for ( int i=0; i<10; i++ ) {
// 獲取包含返回結果的future對象
Future<String> future = results.get(i);
// 從future中取出執行結果(若尚未返回結果,則get方法被阻塞,直到結果被返回爲止)
String result = future.get();
System.out.println(result);
}
此方法的弊端:
- 需要自己創建容器維護所有的返回結果,比較麻煩;
- 從list中遍歷的每個Future對象並不一定處於完成狀態,這時調用get()方法就會被阻塞住,如果系統是設計成每個線程完成後就能根據其結果繼續做後面的事,這樣對於處於list後面的但是先完成的線程就會增加了額外的等待時間。
方法二:使用ExecutorService的invokeAll函數
本方法能解決第一個弊端,即並不需要自己去維護一個存儲返回結果的容器。當我們需要獲取線程池所有的返回結果時,只需調用invokeAll函數即可。
但是,這種方式需要你自己去維護一個用於存儲任務的容器。
// 創建一個線程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
// 創建存儲任務的容器
List<Callable<String>> tasks = new ArrayList<Callable<String>>();
// 提交10個任務
for ( int i=0; i<10; i++ ) {
Callable<String> task = new Callable<String>(){
public String call(){
int sleepTime = new Random().nextInt(1000);
Thread.sleep(sleepTime);
return "線程"+i+"睡了"+sleepTime+"秒";
}
};
executorService.submit( task );
// 將task添加進任務隊列
tasks.add( task );
}
// 獲取10個任務的返回結果
List<Future<String>> results = executorService.invokeAll( tasks );
// 輸出結果
for ( int i=0; i<10; i++ ) {
// 獲取包含返回結果的future對象
Future<String> future = results.get(i);
// 從future中取出執行結果(若尚未返回結果,則get方法被阻塞,直到結果被返回爲止)
String result = future.get();
System.out.println(result);
}
方法三:使用CompletionService
CompletionService內部維護了一個阻塞隊列,只有執行完成的任務結果纔會被放入該隊列,這樣就確保執行時間較短的任務率先被存入阻塞隊列中。
ExecutorService exec = Executors.newFixedThreadPool(10);
final BlockingQueue<Future<String>> queue = new LinkedBlockingDeque<Future<String>>(
10);
//實例化CompletionService
final CompletionService<String
> completionService = new ExecutorCompletionService<String>(
exec, queue);
// 提交10個任務
for ( int i=0; i<10; i++ ) {
final int tmp = i;
completionService
.submit( new Callable<String>(){
public String call(){ int sleepTime = new Random().nextInt(1000); Thread.sleep(sleepTime); return "線程"+tmp+"睡了"+sleepTime+"秒"; } } );}// 輸出結果
for ( int i=0; i<10; i++ ) {
// 獲取包含返回結果的future對象(若整個阻塞隊列中還沒有一條線程返回結果,那麼調用take將會被阻塞,當然你可以調用poll,不會被阻塞,若沒有結果會返回null,poll和take返回正確的結果後會將該結果從隊列中刪除)
Future<String> future = completionService.take();
// 從future中取出執行結果,這裏存儲的future已經擁有執行結果,get不會被阻塞
String result = future.get();
System.out.println(result);
}
轉自:http://blog.csdn.net/u010425776/article/details/54580710