前言:
本章介紹goole Guava 包的 ListenableFuture,也就是開源的Java Library Guaa中的一個併發編程的輔助類,它笨神是繼承是java的Future。併發是一個很難的問題,但它是由具有強大和簡單的抽象工作顯著簡化。爲了簡化事情,Guava擴展了來自JDK的Future從而得到ListenableFuture。併發編程是一個難題,但是一個強大而簡單的抽象可以顯著的簡化併發的編寫。出於這樣的考慮,Guava 定義le ListenableFuture
。
我們強烈地建議你在代碼中多使用ListenableFuture來代替JDK的 Future,
因爲:
- *大多數Futures 方法中需要它。
- *轉到ListenableFuture 編程比較容易。
- *Guava提供的通用公共類封裝了公共的操作方方法,不需要提供Future和ListenableFuture的擴展方法。
接口:
ListenableFuture 中的基礎方法是addListener(Runnable,
Executor)
該方法會在多線程運算完的時候,指定的Runnable參數傳入的對象會被指定的Executor執行。
添加回調(Callbacks):
大多數用戶喜歡使用Futures.addCallback(ListenableFuture<V>,
FutureCallback<V>, Executor)
,或默認使用的版本MoreExecutors.sameThreadExecutor()
,以便在回調快速輕便時使用。A FutureCallback<V>
實現兩種方法:
onSuccess(V)
在Future執行成功時去執行,取得成功的結果onFailure(Throwable)
,在Future執行失敗時去執行失敗, 取得失敗的結果
創建:
ExecutorService.submit(Callable)
的方法來啓動異步計算,Guava提供的ListeningExecutorService
接口,它ListenableFuture
,而
ExecutorService
將返回普通的Future
。要轉換ExecutorService
成一個ListeningExecutorService
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)
將其轉換Future
爲ListenableFuture
。儘可能地採用修改原生的代碼返回 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>接口
。 CheckedFuture
是ListenableFuture,
包含可以拋出被檢查異常的多個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<>()