Guava文件翻譯之ListenableFuture

devos發表於2016-01-21

 

ListenableFutureExplained

併發是一個困難的問題,但是使用強大而簡單的抽象可以極大地簡化併發問題。為了簡化事情,Guava使用ListenableFuture繼承了JDK的Future介面.

我們強烈建議你在所在程式碼裡總是使用ListenableFuture,而不是Future,因為:

  • 大多數Future相關的介面需要它
  • 這比以後換成ListenableFuture更容易
  • 工具的提供者不需要為它們的方法分別提供Future和ListenableFuture的變體

介面 Interface

一個傳統的Future代表一個非同步計算的結果:一個可能已經得到結果或者還沒結束的計算。一個Future可以作為一個正在進行中的計算的控制程式碼(handle), 作為一個服務對我們的保證(promise),保證它會提供給我們一個結果。

一個ListenableFuture允許我們註冊一個在計算完成時會執行的回撥(callback),如果計算已經完成,就會立即執行回撥。這個增加的簡單功能可以讓ListenableFuture支援很多基本的Future介面所不支援的操作。

ListenableFuture所增加的基本操作是addListener(Runnable, Executor), 它指明當這個Future代表的計算完成時,特定的Runnable將會在特定的Executor中執行。

填加回撥 Adding Callbacks 

大多數使用者傾向於使用Futures.addCallback(ListenableFuture<V>, FutureCallback<V>, Executor),或者另一個預設使用MoreExecutors.sameThreadExecutor的版本,來在回撥執行快速並且輕量的時候使用。一個需要實現兩個方法 FutureCallback<V>

  • onSuccess(V),在future成功時執行的動作,基於future的結果。
  • onFailure(Throwable)當future失敗時執行的動作,基於失敗的原因。

建立 Creation

與JDK使用ExecutorService.submit(Callable)的方式來初始化一個非同步的計算相類似,Guava提供了介面ListeningExecutorService,它會返回一個ListenableFuture而不像ExecutorService那樣返回一個Future。如果想要把一個ExecutorService轉化為一個ListeningExecutorService,只需要使用MoreExecutors.listeningDecorator(ExecutorService)。

ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() {
  public Explosion call() {
    return pushBigRedButton();
  }
});
Futures.addCallback(explosion, new FutureCallback<Explosion>() {
  // we want this handler to run immediately after we push the big red button!
  public void onSuccess(Explosion explosion) {
    walkAwayFrom(explosion);
  }
  public void onFailure(Throwable thrown) {
    battleArchNemesis(); // escaped the explosion!
  }
});

或者,如果你之前用的是基於FutureTask的API,Guava提供了ListenableFutureTask.create(Callable<V>) 以及ListenableFutureTask.create(Runnable, V)。不像JDK,ListenableFutureTask並不是用來直接繼承的。

如果你想要這樣的抽象:你想直接設定future的值,而不是實現一個方法來計算這個值,考慮下繼承 AbstractFuture<V> ,或者直接使用SettableFuture

如果你必須把其它API提供的Future轉成ListenableFuture,你可能別無選擇,而必須使用重量級 JdkFutureAdapters.listenInPoolThread(Future)的來把一個Future轉成ListenableFuture. 只要情況允許,更好的選擇就是修改原來的程式碼,讓它返回一個ListenableFuture。

 

應用 Application

(譯註:這個application應該理解成apply的名詞,是'apply a function to a value'裡的apply的意思, 請從函數語言程式設計的角度理解)

使用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.transform(rowKeyFuture, queryFunction, queryExecutor);

(譯註:如果懂Scala的話,這段程式碼大體相當於rowKeyFuture.map(dataService.read)(queryExecutor), 要短了非常多,也更好理解。但是Scala的Future好像不像ListenableFuture可以註冊多個監聽器)

有很多其它的操作也可以被ListenableFuture高效的支援,但是Future就不行。不同的操作可以在不同的executor中執行,一個ListenableFuture也可以有多個等待執行的動作。

當很多個操作都要在另一個操作開始後立即執行--也就是扇出(fan-out)--ListenableFuture可以做到這點:它可以觸發所有那些的需要執行的回撥。多做一點工作,我們就可以扇入(fan-in),或者觸發一個ListenableFuture,在其它所有的Future都完成以後,它會立即執行: 一個例子是the implementation of Futures.allAsList

 

MethodDescriptionSee also
transform(ListenableFuture<A>, AsyncFunction<A, B>, Executor)* Returns a newListenableFuturewhose result is the product of applying the givenAsyncFunction to the result of the givenListenableFuture. transform(ListenableFuture<A>, AsyncFunction<A, B>)
transform(ListenableFuture<A>, Function<A, B>, Executor) Returns a newListenableFuturewhose result is the product of applying the given Functionto the result of the givenListenableFuture. transform(ListenableFuture<A>, Function<A, B>)
allAsList(Iterable<ListenableFuture<V>>) Returns aListenableFuturewhose value is a list containing the values of each of the input futures, in order. If any of the input futures fails or is cancelled, this future fails or is cancelled. allAsList(ListenableFuture<V>...)
successfulAsList(Iterable<ListenableFuture<V>>) Returns aListenableFuturewhose value is a list containing the values of each of the successful input futures, in order. The values corresponding to failed or cancelled futures are replaced with null. successfulAsList(ListenableFuture<V>...)

 

Method 方法Description 描述See also 參見
transform(ListenableFuture<A>, AsyncFunction<A, B>, Executor)*

Returns a newListenableFuture whose result is the product of applying the given AsyncFunction to the result of the given ListenableFuture.

返回一個新的ListenableFuture, 它的結果是把給定的ListenableFuture的結果應用於給定的非同步函式的結果(譯註:意思是把給定的ListenableResult的result作為引數呼叫給定的非同步函式)

transform(ListenableFuture<A>, AsyncFunction<A, B>)
transform(ListenableFuture<A>, Function<A, B>, Executor)

Returns a new ListenableFuture whose result is the product of applying the given Functionto the result of the given ListenableFuture.

返回一個新的ListenableFuture,它的結果是把給定的ListenableFuture的結果應用於給定的函式的結果

transform(ListenableFuture<A>, Function<A, B>)
allAsList(Iterable<ListenableFuture<V>>)

Returns a ListenableFuture whose value is a list containing the values of each of the input futures, in order. If any of the input futures fails or is cancelled, this future fails or is cancelled.

返回一個新的ListenableFuture,它的結果一個list, 這個list包括了給定的一系列ListenableFuture的結果,list的元素按照這些給定的ListenableFuture的順序。如果給定的這些futures中有任何一個被取消了或者失敗了,被返回的這個ListenableFuture就會被取消或失敗。

allAsList(ListenableFuture<V>...)
successfulAsList(Iterable<ListenableFuture<V>>)

Returns aListenableFuturewhose value is a list containing the values of each of the successful input futures, in order. The values corresponding to failed or cancelled futures are replaced with null.

返回一個新的ListenableFuture,它的值是一個list,這個list包括了每一個成功執行的future,按照給出的順序。跟失敗或者被取消的future相關的值會被設成null

successfulAsList(ListenableFuture<V>...)

* An AsyncFunction<A, B> provides one method, ListenableFuture<B> apply(A input). It can be used to asynchronously transform a value.

 一個提供了一個方法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,包括了各種版本的可以丟擲受檢異常的方法。這使得建立一個執行邏輯可能丟擲異常的Future更加容易。如果想要把一個ListenableFuture轉成一個CheckedFuture, 可以使用Futures.makeChecked(ListenableFuture<V>, Function<Exception, X>).


 

總結:

ListenableFuture提供了很有價值的對JDK併發庫的補充。不過同樣的功能,Scala提供的Future的功能要更強大,而且Scala的語法也使得程式碼更簡單易懂。實際上,Promise也是很強大的一種抽象,這篇Guava的文章只簡單提了一下SettableFuture。想要更深入瞭解的可以看一下Scala的文件,這個有人翻譯了,頁面的右上角可以選擇中文版。

Futures and Promises

 

相關文章