1. 程式人生 > >Java併發程式設計實戰--FutureTask

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