Guava學習之ListenableFuture

本文是對 Guava 中 ListenableFuture 的學習介紹。歡迎加入學習項目: LearningGuava肥惭。

以下參考: 官方文檔

處理并發(fā)是一個很困難的問題盯仪,但是我們可以通過使用功能強大的抽象來簡化這個工作。為了簡化這個問題蜜葱,Guava 提供了 ListenableFuture全景,它繼承了 JDK 中的 Future 接口。

我們強烈建議:在你的代碼中牵囤,使用 ListenableFuture 來替代 Future爸黄,因為

  • 很多 Future 相關的方法需要它。
  • 一開始就使用 ListenableFuture 會省事很多揭鳞。
  • 這樣工具方法提供者就不需要針對 FutureListenableFuture 都提供方法炕贵。

接口

Future 代表了異步執(zhí)行的結果:一個可能還沒有產(chǎn)生結果的執(zhí)行過程。 Future 可以正在被執(zhí)行野崇,但是會保證返回一個結果称开。

ListenableFuture 可以使你注冊回調(diào)函數(shù),使得在結果計算完成的時候可以回調(diào)你的函數(shù)乓梨。如果結果已經(jīng)算好鳖轰,那么將會立即回調(diào)。這個簡單的功能使得可以完成很多 Future 支持不了的操作扶镀。

ListenableFuture 添加的基本函數(shù)是 addListener(Runnable, Executor)蕴侣。通過這個函數(shù),當 Future 中的結果執(zhí)行完成時臭觉,傳入的 Runnable 會在傳入的 Executor 中執(zhí)行昆雀。

添加回調(diào)函數(shù)

使用者偏向于使用 Futures.addCallback(ListenableFuture<V>, FutureCallback<V>, Executor) , 或者當需要注冊輕量級的回調(diào)的時候,可以使用默認為 MoreExecutors.directExecutor()版本蝠筑。

FutureCallback<V> 實現(xiàn)了兩個方法:

創(chuàng)建

與 JDK 中 通過 ExecutorService.submit(Callable) 來初始化一個異步的任務相似菱肖,Guava 提供了一個 ListeningExecutorService 接口客冈,這個接口可以返回一個 ListenableFutureExecutorService 只是返回一個普通的 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 值的抽象,而不是實現(xiàn)一個方法來計算結果亦鳞,那么可以考慮直接擴展 AbstractFuture<V> 或者 SettableFuture馍忽。

如果你一定要將一個基于 Future 的 API 轉換為基于 ListenableFuture 的話,你不得不采用硬編碼的方式 JdkFutureAdapters.listenInPoolThread(Future) 來實現(xiàn)從 FutureListenableFuture 的轉換燕差。所以遭笋,盡可能地使用 ListenableFuture

應用

使用 ListenableFuture 一個最重要的原因就是:可以基于他實現(xiàn)負責的異步執(zhí)行鏈徒探。如下所示:

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);

很多不能被 Future 支持的方法可以通過 ListenableFuture 被高效地支持瓦呼。不同的操作可能被不同的執(zhí)行器執(zhí)行,而且一個 ListenableFuture 可以有多個響應操作测暗。

ListenableFuture 有多個后續(xù)操作的時候央串,這樣的操作稱為:“扇出”。當它依賴多個輸入 future 同時完成時碗啄,稱作“扇入”质和。可以參考 Futures.allAsList的實現(xiàn)稚字。

方法 描述 參考
transformAsync(ListenableFuture<A>, AsyncFunction<A, B>, Executor) 返回新的 ListenableFuture饲宿,它是給定 AsyncFunction 結合的結果 transformAsync(ListenableFuture<A>, AsyncFunction<A, B>)
transform(ListenableFuture<A>, Function<A, B>, Executor) 返回新的 ListenableFuture,它是給定 Function 結合的結果 transform(ListenableFuture<A>, Function<A, B>)
allAsList(Iterable<ListenableFuture<V>>) 返回一個 ListenableFuture,它的值是一個輸入 futures 的值的按序列表,任何一個 future 的失敗都會導致最后結果的失敗 allAsList(ListenableFuture<V>...)
successfulAsList(Iterable<ListenableFuture<V>>) 返回一個 ListenableFuture,它的值是一個輸入 futures 的成功執(zhí)行值的按序列表尉共,對于取消或者失敗的任務褒傅,對應的值是 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);

避免嵌套 Future

在使用通用接口返回 Future 的代碼中霹菊,很有可能會嵌套 Future剧蚣。例如:

executorService.submit(new Callable<ListenableFuture<Foo>() {
  @Override
  public ListenableFuture<Foo> call() {
    return otherExecutorService.submit(otherCallable);
  }
});

上述代碼將會返回:ListenableFuture<ListenableFuture<Foo>>。這樣的代碼是不正確的旋廷,因為外層 future 的取消操作不能傳遞到內(nèi)層的 future鸠按。此外,一個常犯的錯誤是:使用 get() 或者 listener 來檢測其它 future 的失敗饶碘。為了避免這樣的情況目尖,Guava 所有處理 future 的方法(以及一些來自 JDK 的代碼)具有安全解決嵌套的版本。

CheckedFuture

Guava 也提供 CheckedFuture<V, X extends Exception> 接口扎运。

CheckedFuture 是這樣的一個 ListenableFuture:具有多個可以拋出受保護異常的 get 方法瑟曲。這使得創(chuàng)建一個執(zhí)行邏輯可能拋出異常的 future 變得容易饮戳。使用 Futures.makeChecked(ListenableFuture<V>, Function<Exception, X>)可以將 ListenableFuture 轉換為 CheckedFuture

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洞拨,一起剝皮案震驚了整個濱河市扯罐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌烦衣,老刑警劉巖歹河,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異花吟,居然都是意外死亡秸歧,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門示辈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寥茫,“玉大人,你說我怎么就攤上這事矾麻∩闯埽” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵险耀,是天一觀的道長弄喘。 經(jīng)常有香客問我,道長甩牺,這世上最難降的妖魔是什么蘑志? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮贬派,結果婚禮上急但,老公的妹妹穿的比我還像新娘。我一直安慰自己搞乏,他們只是感情好波桩,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著请敦,像睡著了一般镐躲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上侍筛,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天萤皂,我揣著相機與錄音,去河邊找鬼匣椰。 笑死裆熙,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播入录,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼齐媒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了纷跛?” 一聲冷哼從身側響起喻括,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贫奠,沒想到半個月后唬血,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡唤崭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年拷恨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谢肾。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡腕侄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芦疏,到底是詐尸還是另有隱情冕杠,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布酸茴,位于F島的核電站分预,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏薪捍。R本人自食惡果不足惜笼痹,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酪穿。 院中可真熱鬧凳干,春花似錦、人聲如沸被济。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缠黍。三九已至揍瑟,卻和暖如春少欺,著一層夾襖步出監(jiān)牢的瞬間喳瓣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工赞别, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留畏陕,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓仿滔,卻偏偏與公主長得像惠毁,于是被迫代替她去往敵國和親犹芹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理鞠绰,服務發(fā)現(xiàn)腰埂,斷路器,智...
    卡卡羅2017閱讀 134,652評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,077評論 25 707
  • 在現(xiàn)代軟件開發(fā)中蜈膨,系統(tǒng)功能越來越復雜屿笼,管理復雜度的方法就是分而治之,系統(tǒng)的很多功能可能會被切分為小的服務翁巍,對外提供...
    天堂鳥6閱讀 7,149評論 0 23
  • 2017年3月20日,給外公打電話驰凛,正巧他們睡覺(其實我今晚放學回宿舍已經(jīng)速度很快了胸懈,并不知道他們已經(jīng)休息),外婆...
    陌熊閱讀 215評論 0 2
  • 他工作總是早出晚歸、馬不停蹄渔隶,經(jīng)常應酬到很晚才回家羔挡。 昨天等到半夜他才回來,一開門看到他喝多了身體很不舒服的樣子间唉,...
    Rainven宜兒閱讀 1,221評論 8 50