執(zhí)行器框架的優(yōu)質(zhì)之一是可以并發(fā)地執(zhí)行任務,并將任務執(zhí)行結果返回。要想實現(xiàn)這個功能,需要JDK中的兩個接口。
- Callable:這個接口帶有一個call()方法,你可以在這個方法里面實現(xiàn)任務執(zhí)行邏輯,同時這個接口帶有一個泛型參數(shù),你可以通過這個泛型參數(shù)來指定返回結果的類型。
- Future:這個接口生命了一些方法來獲取由Callable對象產(chǎn)生的結果,并管理他們的狀態(tài)。
創(chuàng)建一個類FactorialCalculator實現(xiàn)Callable接口,用于計算階乘。泛型參數(shù)使用Integer來規(guī)定返回值為整型。
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
/**
* 創(chuàng)建一個名為FactorialCalculator類并實現(xiàn)Callable<Integer>接口
*
* 用來計算number的階乘
*
* Created by hadoop on 2016/11/2.
*/
public class FactorialCalculator implements Callable<Integer> {
private Integer number;
public FactorialCalculator(Integer number) {
this.number = number;
}
@Override
public Integer call() throws Exception {
int result = 1;
if (number > 2) {
for (int i = 2; i <= number; i++) {
result *= i;
}
}
TimeUnit.MILLISECONDS.sleep(200);
return result;
}
}
然后實現(xiàn)Main方法,循環(huán)10次,每次產(chǎn)生一個隨機整數(shù),然后調(diào)用FactorialCalculator來求這個整數(shù)的階乘。注意這里使用submit()方法來提交callable任務,因為這個方法會返回一個Future對象,而不是前面兩節(jié)那樣使用的是execute方法來執(zhí)行Runnable。
使用Futuee對象不但可以用來獲取線程任務的返回值,還可以用于獲取線程執(zhí)行狀態(tài)。
- isDone():用于檢查任務是否執(zhí)行完成。
- get():用于獲取Callable的call()方法執(zhí)行的返回結果,get()方法將一直等待call()方法執(zhí)行完成。如果等待過程中線程中斷了,那么將拋出InterrupedException異常,如果call()方法執(zhí)行異常,那么get()方法將接著拋出ExecutionException。
- get(long timeout, TimeUnit unit):等待一段時間,如果任務沒有執(zhí)行完畢,那么返回null。
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
/**
* 在執(zhí)行器中執(zhí)行任務并返回結果
*
* 執(zhí)行器框架的優(yōu)勢之一在于可以并行執(zhí)行任務,并且返回結果。Java并發(fā)API通過以下兩個接口來s實現(xiàn)這個功能。
* 1. Callable接口:這個借口生命了call()方法,你可以在這個方法中實現(xiàn)具體的處理邏輯。
* Callable接口帶有泛型參數(shù),這意味著call()方法可以返回該數(shù)據(jù)類型的對象。
* 2. Future接口:這個接口用來接收Callable接口產(chǎn)生的結果,并管理他們的狀態(tài)。
*
* 在本節(jié)我們學習了使用Callable接口來啟動并發(fā)任務并返回結果。
* 我么編寫了FactorialCalculator類,它實現(xiàn)了帶有泛型參數(shù)Integer的Callable接口。
* 因此這個Integer類型將作為在調(diào)用call()方法的返回值類型。
*
* 另一個關鍵點在于Main類,在這個類中我們使用了submit()方法,發(fā)送一個Callable對象到執(zhí)行器中。
* 這個submit()方法接收Callable對象作為參數(shù),然后返回Future對象。
* Future對象可以用于以下兩個目的。
* 1. 控制任務的狀態(tài):可以取消或者檢查任務是否完成。在這里我們使用了isDone方法來判斷任務是否完成。
* 2. 通過get()方法,接收call()方法返回的結果。這個方法一直等到call()方法執(zhí)行完成并返回結果。
* 如果get()方法在等待結果時線程中斷了,將拋出一個InterruptedException。
* 如果call()方法拋出異常,那么get方法拋出ExecutionException。
*
* Future對象還聽了另一個future.get(1000, TimeUnit.NANOSECONDS)方法來接受返回值。
* 如果等待(1000, TimeUnit.NANOSECONDS)時間,call()方法還沒有執(zhí)行結束,那么將直接返回null值。
*
* Created by hadoop on 2016/11/2.
*/
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(2);
List<Future<Integer>> futures = new ArrayList<Future<Integer>>();
Random random = new Random();
for (int i = 0; i < 10; i++) {
Integer number = random.nextInt(10);
FactorialCalculator calculator = new FactorialCalculator(number);
Future<Integer> future = executor.submit(calculator);
futures.add(future);
}
do {
//System.out.printf("Main: Number of the completed Tasks: %d\n", executor.getCompletedTaskCount());
for (int i = 0; i < futures.size(); i++) {
Future<Integer> future = futures.get(i);
//System.out.printf("Main: Tasks %d: %s\n", i, future.isDone());
}
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (executor.getCompletedTaskCount() < futures.size());
for (int i = 0; i < futures.size(); i++) {
Future<Integer> future = futures.get(i);
System.out.printf("Main: Tasks %d: %d\n", i, future.get());
//System.out.printf("Main: Tasks %d: %d\n", i, future.get(1000, TimeUnit.NANOSECONDS));
}
executor.shutdown();
}
}