- 引入 Callable + Future
- Callable + Future例項
引入 Callable + Future
Executor框架的優勢之一就是,可以執行併發任務並且返回結果。 我們知道Runnable物件是沒有返回值的,所以自然利用Runnable物件就無法返回結果,於是就定義了一個新的介面,可以理解為是“帶有返回值的Runnable物件”。 這個介面就是 Callable介面:這個介面宣告瞭一個call方法,類似於Runnable介面的run方法,是任務具體的邏輯,不同就在於可以有返回值,而且這個介面是一個泛型介面,這就意味著必須宣告call方法的返回型別。
我們任務交給執行緒執行之後,什麼時候執行結束,將結果返回這個時間往往是無法具體確定的,所以為了接受這個來自未來某個時刻執行完之後的返回結果,又新增了一個Future介面: Future介面:這個介面宣告瞭一些方法獲取由callable物件產生的結果,並管理他們的狀態。
Callable + Future例項
接下來,我們編寫一個例項來接受任務的返回結果
實現一個Callable物件,由於返回值是Integer,所以定義為Callable
package CreateExecutorCallableFuture;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
public class FactorialCaculator implements Callable<Integer> {
private Integer number;
public FactorialCaculator(Integer number) {
super();
this.number = number;
}
@Override
public Integer call() throws Exception {
int result = 1;
if((number == 0) || (number == 1))
return 1;
else {
for(int i=2;i<=number;i++) {
result *= i;
TimeUnit.MILLISECONDS.sleep(20);
}
}
System.out.printf("%s : %d\n",Thread.currentThread().getName(),result);
return result;
}
}
複製程式碼
Main類建立一個執行緒池來執行這些任務,並在任務執行完之後輸出結果
package CreateExecutorCallableFuture;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(2);
List<Future<Integer>> resList = new ArrayList<>();
Random random = new Random();
for(int i=0;i<10;i++) {
Integer number = random.nextInt(10);
FactorialCaculator caculator = new FactorialCaculator(number);
Future<Integer> res = executor.submit(caculator);
resList.add(res);
}
do {
System.out.println("Main : Number of CompleteTasks : " + executor.getCompletedTaskCount());
for(int i=0;i<resList.size();i++) {
Future<Integer> res = resList.get(i);
System.out.printf("Main : task %d : %s\n", i, res.isDone());
}
TimeUnit.MILLISECONDS.sleep(50);
}while(executor.getCompletedTaskCount() < resList.size());
for(int i=0;i<resList.size();i++) {
Future<Integer> res = resList.get(i);
Integer number = null;
try {
number = res.get();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.printf("Main : Task %d : %s\n",i,number);
}
}
}
複製程式碼
執行結果
Main : Number of CompleteTasks : 0
Main : task 0 : false
Main : task 1 : false
Main : task 2 : false
Main : task 3 : false
Main : task 4 : false
Main : task 5 : false
Main : task 6 : false
Main : task 7 : false
Main : task 8 : false
Main : task 9 : false
pool-1-thread-1 : 24
pool-1-thread-2 : 120
Main : Number of CompleteTasks : 2
Main : task 0 : true
Main : task 1 : true
Main : task 2 : false
Main : task 3 : false
Main : task 4 : false
Main : task 5 : false
Main : task 6 : false
Main : task 7 : false
Main : task 8 : false
Main : task 9 : false
pool-1-thread-2 : 2
pool-1-thread-2 : 2
Main : Number of CompleteTasks : 4
Main : task 0 : true
Main : task 1 : true
Main : task 2 : false
Main : task 3 : true
Main : task 4 : true
Main : task 5 : false
Main : task 6 : false
Main : task 7 : false
Main : task 8 : false
Main : task 9 : false
pool-1-thread-2 : 6
Main : Number of CompleteTasks : 6
Main : task 0 : true
Main : task 1 : true
Main : task 2 : false
Main : task 3 : true
Main : task 4 : true
Main : task 5 : true
Main : task 6 : true
Main : task 7 : false
Main : task 8 : false
Main : task 9 : false
pool-1-thread-1 : 40320
Main : Number of CompleteTasks : 7
Main : task 0 : true
Main : task 1 : true
Main : task 2 : true
Main : task 3 : true
Main : task 4 : true
Main : task 5 : true
Main : task 6 : true
Main : task 7 : false
Main : task 8 : false
Main : task 9 : false
pool-1-thread-2 : 720
Main : Number of CompleteTasks : 9
Main : task 0 : true
Main : task 1 : true
Main : task 2 : true
Main : task 3 : true
Main : task 4 : true
Main : task 5 : true
Main : task 6 : true
Main : task 7 : true
Main : task 8 : false
Main : task 9 : true
Main : Number of CompleteTasks : 9
Main : task 0 : true
Main : task 1 : true
Main : task 2 : true
Main : task 3 : true
Main : task 4 : true
Main : task 5 : true
Main : task 6 : true
Main : task 7 : true
Main : task 8 : false
Main : task 9 : true
pool-1-thread-1 : 362880
Main : Task 0 : 24
Main : Task 1 : 120
Main : Task 2 : 40320
Main : Task 3 : 2
Main : Task 4 : 2
Main : Task 5 : 6
Main : Task 6 : 1
Main : Task 7 : 720
Main : Task 8 : 362880
Main : Task 9 : 1
複製程式碼
Future物件主要有一下兩個目的:
-
控制任務的狀態:可以取消和檢查任務是否完成。可以使用isDone檢查任務是否完成,檢查isCancel檢查任務是否暫停,也可以直接呼叫cancle方法暫停任務。
-
通過call方法獲取返回結果,為了達到這個目的,可以使用get方法,這個方法會一直等到callable物件的call方法返回結果。如果此時任務尚未完成,get方法就會一直阻塞到執行緒完成。
** Future物件是用來管理Callavle任務的!**