Guava包中的ListenableFuture詳情解析

前言:

本章介紹goole Guava 包的 ListenableFuture,也就是開源的Java Library Guaa中的一個併發編程的輔助類,它笨神是繼承是java的Future。併發是一個很難的問題,但它是由具有強大和簡單的抽象工作顯著簡化。爲了簡化事情,Guava擴展了來自JDK的Future從而得到ListenableFuture。

併發編程是一個難題,但是一個強大而簡單的抽象可以顯著的簡化併發的編寫。出於這樣的考慮,Guava 定義le ListenableFuture

我們強烈地建議你在代碼中多使用ListenableFuture來代替JDK的 Future, 因爲:

  • *大多數Futures 方法中需要它。
  • *轉到ListenableFuture 編程比較容易。
  • *Guava提供的通用公共類封裝了公共的操作方方法,不需要提供Future和ListenableFuture的擴展方法。

接口:

傳統JDK中的Future通過異步的方式計算返回結果:在多線程運算中可能或者可能在沒有結束返回結果,Future是運行中的
線程的一個引用句柄,確保在服務執行返回一個Result。
ListenableFuture可以允許你註冊回調方法(callbacks),在運算(多線程執行)完成的時候進行調用,  或者在運算(多線程執行)
完成後立即執行。這樣簡單的改進,使得可以明顯的支持更多的操作,這樣的功能在JDK concurrent包中的Future是不支持的。

  ListenableFuture 中的基礎方法是addListener(Runnable, Executor) 該方法會在多線程運算完的時候,指定的Runnable參數傳入的對象會被指定的Executor執行。

添加回調(Callbacks):

大多數用戶喜歡使用Futures.addCallback(ListenableFuture<V>, FutureCallback<V>, Executor),或默認使用版本MoreExecutors.sameThreadExecutor()以便在回調快速輕便時使用。FutureCallback<V>實現兩種方法:

創建:

對應JDK的 ExecutorService.submit(Callable)的方法來啓動異步計算,Guava提供的ListeningExecutorService接口,
返回一個ListenableFuture,而ExecutorService將返回普通的Future要轉換ExecutorService成一個ListeningExecutorService
,只需使用MoreExecutors.listeningDecorator(ExecutorService)來進行裝飾一下即可。

 ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
        com.google.common.util.concurrent.ListenableFuture<Object> submit = service.submit(new Callable<Object>() {
            public Object call(){
                return "回調參數success";
            }
        });
        Futures.addCallback(submit, new FutureCallback<Object>() {
            @Override
            public void onSuccess(Object result) {
                System.out.println("result = " + result);
            }

            @Override
            public void onFailure(Throwable t) {
                System.out.println("t = " + t);

            }
        });
另外,如果你是從FutureTask轉換而來的,Guava的API提供了 ListenableFutureTask.create(Callable<V>)API轉換ListenableFutureTask.create(Runnable, V)和 JDK不同的是, ListenableFutureTask 不能隨意被繼承(譯者注:ListenableFutureTask中的done方法實現了調用listener的操作)。

如果你喜歡抽象的方式來設置Future的值,而不是想實現接口中的方法,可以考慮繼承抽象類
假如你必須將其它API提供的Future轉換成ListenableFuture,沒有別的方法你只能採用硬編碼的方式,使用JdkFutureAdapters.listenInPoolThread(Future)將其轉換FutureListenableFuture儘可能地採用修改原生的代碼返回 ListenableFuture會更好一些。

應用(Application):

使用ListenableFuture最重要的理由是它可以進行一系列的複雜鏈式的異步操作。

ListenableFuture<RowKey> rowKeyFuture = indexService.lookUp(query);
AsyncFunction<RowKey, QueryResult> queryFunction =
  new AsyncFunction<RowKey, QueryResult>() {
    public ListenableFuture<QueryResult> apply(RowKey rowKey) {
      return dataService.read(rowKey);
    }
  };
ListenableFuture<QueryResult> queryFuture =
    Futures.transformAsync(rowKeyFuture, queryFunction, queryExecutor);
許多其他操作可以更有效地支持ListenableFuture,而不能單獨支持Future不同的操作可能由不同的執行者執行,單個操作ListenableFuture可以有多個動作等待。

當一個操作開始的時候其他的一些操作也會盡快開始執行–“fan-out”–ListenableFuture 能夠滿足這樣的場景:促發所有的回調(callbacks)。反之更簡單的工作是,同樣可以滿足“fan-in”場景,促發ListenableFuture 獲取(get)計算結果,同時其它的Futures也會盡快執行:可以參考Futures.allAsList 

fan-in和fan-out是軟件設計的一個術語,可以參考這裏:http://baike.baidu.com/view/388892.htm#1或者看這裏的解析Design Principles: Fan-In vs Fan-Out,這裏fan-out的實現就是封裝的ListenableFuture通過回調,調用其它代碼片段。fan-in的意義是可以調用其它Future

方法 描述 參考
transformAsync(ListenableFuture<A>, AsyncFunction<A, B>, Executor)* 返回一個新的ListenableFuture ,該ListenableFuture 返回的result是由傳入的AsyncFunction 參數指派到傳入的 ListenableFuture中. transformAsync(ListenableFuture<A>, AsyncFunction<A, B>)
transform(ListenableFuture<A>, Function<A, B>, Executor) 返回一個新的ListenableFuture ,該ListenableFuture 返回的result是由傳入的Function 參數指派到傳入的 ListenableFuture中. transform(ListenableFuture<A>, Function<A, B>)
allAsList(Iterable<ListenableFuture<V>>) 返回一個ListenableFuture ,該ListenableFuture 返回的result是一個List,List中的值是每個ListenableFuture的返回值,假如傳入的其中之一fails或者cancel,這個Future fails 或者canceled allAsList(ListenableFuture<V>...)
successfulAsList(Iterable<ListenableFuture<V>>) 返回一個ListenableFuture ,該Future的結果包含所有成功的Future,按照原來的順序,當其中之一Failed或者cancel,則用null替代 successfulAsList(ListenableFuture<V>...)
 AsyncFunction<A, B>提供了一種方法ListenableFuture<B> apply(A input)它可以用於異步轉換一個值。

List<ListenableFuture<QueryResult>> queries;
// The queries go to all different data centers, but we want to wait until they're all done or failed.

ListenableFuture<List<QueryResult>> successfulQueries = Futures.successfulAsList(queries);

Futures.addCallback(successfulQueries, callbackOnSuccessfulQueries);

CheckedFuture

Guava也提供了一個CheckedFuture<V, X extends Exception>接口 CheckedFutureListenableFuture,包含可以拋出被檢查異常的多個get方法的版本。這使得創建一個執行可以更容易地執行可以拋出異常的邏輯。要轉換ListenableFuture成a CheckedFuture,使用Futures.makeChecked(ListenableFuture<V>, Function<Exception, X>)。這樣使得創建一個在執行邏輯中可以拋出異常的Future更加容易 。將 ListenableFuture 轉換成CheckedFuture。使用Futures.makeChecked(ListenableFuture<V>, Function<Exception, X>)

接下來,看一個例子,合併多個人物的結果集

public void test() throws Exception {
        ListeningExecutorService service1 = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
        ListenableFuture<Object> submit1 = service1.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                Thread.sleep(1000);
                System.out.println("call future1");
                return "1";
            }
        });
        com.google.common.util.concurrent.ListenableFuture<Object> submit2 = service1.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                Thread.sleep(1000);
                System.out.println("call future2");
                return "2";
            }
        });
        ListenableFuture<List<Object>> listListenableFuture = Futures.allAsList(submit1, submit2);
        ListenableFuture<String> transform = Futures.transform(listListenableFuture, new AsyncFunction<List<Object>, String>() {
            @Override
            public com.google.common.util.concurrent.ListenableFuture<String> apply(List<Object> input) throws Exception {
                return Futures.immediateFuture(String.format("success future %s",input));
            }
        });

        Futures.addCallback(transform, new FutureCallback<String>() {
            @Override
            public void onSuccess(String result) {
                System.out.println(result.getClass());
                System.out.println("success:"+result);
            }

            @Override
            public void onFailure(Throwable t) {
                System.out.println("error:" + t.getMessage());
            }
        });
        //獲取值
        System.out.println("transform:"+transform.get(3000, TimeUnit.MINUTES));
    }

下面的例子是單個任務:

 public void test3() throws Exception {
        ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
        // 執行任務
        final ListenableFuture<String> listenableFuture =  executorService.submit(new Callable<String>() {
            public String call() throws Exception {
                System.out.println("new task 。。。");
                TimeUnit.SECONDS.sleep(1);
                return "test";
            }

        });
        // 綁定任務以及回調函數
        Futures.addCallback(listenableFuture, new FutureCallback<String>() {
            @Override
            public void onSuccess(String result) {
                String str = "";
                try {
                    str = listenableFuture.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
                System.out.println("integer:" + str);
                System.out.println("result:" + result);
            }

            @Override
            public void onFailure(Throwable t) {
                System.out.println("error" + t.getMessage());
            }}
        );
        System.out.println("listenableFuture:" + listenableFuture.get());
    }
其實除了JDK和Google有Future以外,Spring框架也提供一套Future.下面我們來看一個例子:


ListenableFuture<String> listenableFuture = asyncService.asynGet2();
        SuccessCallback<String> successCallback = new SuccessCallback() {
            @Override
            public void onSuccess(Object result) {
                System.out.println("異步回調success: result :"+result);
            }
        };

        FailureCallback failureCallback = new FailureCallback() {
            @Override
            public void onFailure(Throwable ex) {
                System.out.println("異步回調失敗:"+ ex.getMessage());
            }
        };
        listenableFuture.addCallback(successCallback,failureCallback);
        Assert.assertEquals("123",listenableFuture.get());
asyncService 是一個異步Service類,ListenableFuture的返回類型必須通過 new AsyncResult<>()來返回方法的結果集:
new AsyncResult<>()




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章