Java併發程式設計實戰--FutureTask
FutureTask也可以用作閉鎖。(FutureTask實現了Future語義,表示一種抽象的可生成結果的計算。FutureTask表示的計算是通過Callable來實現的,相當於一種可生成結果的Runnable,並且可以處於以下3種狀態:等待執行(Waiting to run),正在執行(Running)和執行完成(Completed)。”執行完成”表示計算的所有可能結束方式,包括正常結束、由於取消而結束和由於異常而結束等。當FutureTask進入完成狀態後,它會停止在這個狀態上。
Future.get的行為取決於任務的狀態。如果任務已經完成,那麼get會立即返回結果,否則get將阻塞直到任務進入完成狀態,然後返回結果或者丟擲異常。FutureTask將計算結果從執行計算的執行緒到獲取這個結果的執行緒,而FutureTask的規範確保了這種傳遞過程能實現結果的安全釋出。
FutureTask在Executor框架中表示非同步任務,此外還可以用來表示一些時間較長的計算,這些計算可以在使用計算結果之前啟動。
public class Preloader {
ProductInfo loadProductInfo() throws DataLoadException, InterruptedException {
System.out.println("loadProductInfo start");
Thread.sleep(1000 * 10);
System.out.println("loadProductInfo end" );
return null;
}
private final FutureTask<ProductInfo> future =
new FutureTask<>(() -> loadProductInfo());
private final Thread thread = new Thread(future);
public void start() {
thread.start();
System.out.println("start");
}
public ProductInfo get()
throws DataLoadException, InterruptedException {
try {
System.out.println("get start");
ProductInfo per = future.get();
System.out.println("get end");
return per;
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof DataLoadException)
throw (DataLoadException) cause;
else {
// throw LaunderThrowable.launderThrowable(cause);
return null;
}
}
}
interface ProductInfo {
}
}
class DataLoadException extends Exception {
}
Preloader建立了一個FutureTask,其中包含從資料庫載入產品資訊的任務,以及一個執行運算的執行緒。由於在建構函式或靜態初始化方法中啟動執行緒並不是一種好方法,因此提供了一個start方法來啟動執行緒。當程式雖有需要ProductInfo時,可以呼叫get方法,如果資料已經載入,那麼將返回這些資料,否則將等待載入完成後再返回。
Callable表示的任務可以丟擲受檢查的或未受檢查的異常,並且任何程式碼都可能丟擲一個Error。無論任務程式碼丟擲什麼異常,都會被封裝到一個ExecutionException中,並在Future.get中被重新丟擲。這將使呼叫get的程式碼變得複雜,因為它不僅需要處理可能出現的ExecutionException(以及未檢查的CancellationException),而且還由於ExecutionException是作為一個Throwable類返回的,因此處理起來並不容易。
Preloader preloader=new Preloader();
preloader.start();
preloader.get();
輸出
start
get start
loadProductInfo start
loadProductInfo end
get end