国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Java中使用CompletableFuture處理異步超時

開發 后端
一天,我在改進多線程代碼時被Future.get()卡住了。

一天,我在改進多線程代碼時被Future.get()卡住了。

Java中使用CompletableFuture處理異步超時

public void serve() throws InterruptedException, ExecutionException, TimeoutException {
  final Future<Response> responseFuture = asyncCode();
  final Response response = responseFuture.get(1, SECONDS);
  send(response);
}
private void send(Response response) {
  //...
}

這是用Java寫的一個Akka應用程序,使用了一個包含1000個線程的線程池(原來如此!)——所有的線程都在阻塞在這個 get() 中。系統的處理速度跟不上并發請求的數量。重構以后,我們干掉了所有的這些線程僅保留了一個,極大的減少了內存的占用。我們簡單一點,通過一個Java 8的例子來演示。***步是使用CompletableFuture來替換簡單的Future(見:Tip 9)。

  • 通過控制任務提交到ExecutorService的方式:只需用 CompletableFuture.supplyAsync(…, executorService) 來代替 executorService.submit(…) 即可
  • 處理基于回調函數的API:使用promises

否則(如果你已經使用了阻塞式的API或 Future<T>)會導致很多線程被阻塞。這就是為什么現在這么多異步的API都讓人很煩了。所以,讓我們重寫之前的代碼來接收CompletableFuture:

public void serve() throws InterruptedException, ExecutionException, TimeoutException {
    final CompletableFuture<Response> responseFuture = asyncCode();
    final Response response = responseFuture.get(1, SECONDS);
    send(response);
}

很明顯,這不能解決任何問題,我們還必須利用新的風格來編程:

public void serve() {
    final CompletableFuture<Response> responseFuture = asyncCode();
    responseFuture.thenAccept(this::send);
}

這個功能上是等同的,但是 serve() 只會運行一小段時間(不會阻塞或等待)。只需要記住:this::send 將會在完成 responseFuture 的同一個線程內執行。如果你不想花費太大的代價來重載已經存在的線程池或send()方法,可以考慮通過 thenAcceptAsync(this::send, sendPool) 好極了,但是我們失去了兩個重要屬性:異常傳播與超時。異常傳播很難實現,因為我們改變了API。當serve()存在的時候,異步操作可能還沒有完成。 如果你關心異常,可以考慮返回 responseFutureor 或者其他可選的機制。至少,應該有異常的日志,否則該異常就會被吞噬了。

final CompletableFuture<Response> responseFuture = asyncCode();
responseFuture.exceptionally(throwable -> {
    log.error("Unrecoverable error", throwable);
    return null;
});

請小心上面的代碼:exceptionally() 試圖從失敗中恢復過來,返回一個可選的結果。這個地方雖可以正常的工作,但是如果對 exceptionally()和withthenAccept() 使用鏈式調用,即使失敗了也還是會調用 send() 方法,返回一個null參數,或者任何其它從 exceptionally() 方法中返回的值。

responseFuture
    .exceptionally(throwable -> {
        log.error("Unrecoverable error", throwable);
        return null;
    })
    .thenAccept(this::send);  //probably not what you think

丟失一秒超時的問題非常巧妙。我們原始的代碼在Future完成之前最多等待(阻塞)1秒,否則就會拋出 TimeoutException。我們丟失了這個功能,更糟糕的是,單元測試超時的不是很方便,經常會跳過這個環節。為了維持超時機制,而又不破壞事件 驅動的原則,我們需要建立一個額外的模塊:一個在給定時間后必定會失敗的 Future。

public static <T> CompletableFuture<T> failAfter(Duration duration) {
    final CompletableFuture<T> promise = new CompletableFuture<>();
    scheduler.schedule(() -> {
        final TimeoutException ex = new TimeoutException("Timeout after " + duration);
        return promise.completeExceptionally(ex);
    }, duration.toMillis(), MILLISECONDS);
    return promise;
}

private static final ScheduledExecutorService scheduler =
        Executors.newScheduledThreadPool(
                1,
                new ThreadFactoryBuilder()
                        .setDaemon(true)
                        .setNameFormat("failAfter-%d")
                        .build());

這個很簡單:我們創建一個promise(沒有后臺任務或線程池的 Future),然后在給定的 java.time.Duration 之后會拋出 TimeoutException 異常。如果在某個地方調用 get() 獲取這個 Future,阻塞的時間到達這個指定的時間后會拋出 TimeoutException。

實際上,它是一個包裝了 TimeoutException 的 ExecutionException,這個無需多說。注意,我使用了固定一個線程的線程池。這不僅僅是為了教學的目的:這是“1個線程應當能滿足任何人 的需求”的場景。failAfter() 本身沒多大的用處,但是如果和 ourresponseFuture 一起使用,我們就能解決這個問題了。

final CompletableFuture<Response> responseFuture = asyncCode();
final CompletableFuture<Response> oneSecondTimeout = failAfter(Duration.ofSeconds(1));
responseFuture
        .acceptEither(oneSecondTimeout, this::send)
        .exceptionally(throwable -> {
            log.error("Problem", throwable);
            return null;
        });

這里還做了很多其他事情。在后臺的任務接收 responseFuture 時,我們也創建了一個“合成”的 oneSecondTimeout future,這在成功的時候永遠不會執行,但是在1秒后就會導致任務失敗。現在我們聯合這兩個叫做 acceptEither,這個操作將執行先完成 Future 的代碼塊,而簡單的忽略 responseFuture 或 oneSecondTimeout 中運行比較慢的那個。如果 asyncCode() 代碼在1秒內執行完成,this::send 就會被調用,而 oneSecondTimeout 異常就不會拋出。但是,如果 asyncCode() 執行真的很慢,oneSecondTimeout 異常就先拋出。由于一個異常導致任務失敗,exceptionallyerror 處理器就會被調用,而不是 this::send 方法。你可以選擇執行 send() 或者 exceptionally,但是不能兩個都執行。當如,如果我們有兩個“普通”的 Future 正常執行完成了,則***響應的那個將調用 send() 方法,后面的就會被丟棄。

這個不是最清晰的解決方案。更清晰的方案是包裝原始的 Future,然后保證它能在給定的時間內執行。這種操作對 com.twitter.util.Future 是可行的(Scala叫做 within()),但是 scala.concurrent.Future 中沒有這個功能(據推測是為了鼓勵使用前面的方式)。我們暫時不討論Scala背后如何執行的,先實現類似 CompletableFuture 的操作。它接受一個 Future 作為輸入,然后返回一個 Future,這個 Future 在后臺任務完成時候執行完成。但是,如果底層的 Future 執行的時間太長,就或拋出異常:

public static <T> CompletableFuture<T> within(CompletableFuture<T> future, Duration duration) {
    final CompletableFuture<T> timeout = failAfter(duration);
    return future.applyToEither(timeout, Function.identity());
}

這引導我們實現最終的、清晰的、靈活的方法:

final CompletableFuture<Response> responseFuture = within(
        asyncCode(), Duration.ofSeconds(1));
responseFuture
        .thenAccept(this::send)
        .exceptionally(throwable -> {
            log.error("Unrecoverable error", throwable);
            return null;
        });

希望你喜歡這篇文章,因為你已經知道在Java里,實現響應式編程不再是什么問題。

責任編輯:王雪燕 來源: ImportNew
相關推薦

2024-12-26 12:59:39

2024-03-06 08:13:33

FutureJDKCallable

2021-03-22 08:45:30

異步編程Java

2021-02-21 14:35:29

Java 8異步編程

2021-06-06 16:56:49

異步編程Completable

2024-04-18 08:20:27

Java 8編程工具

2024-10-14 08:29:14

異步編程任務

2020-05-29 07:20:00

Java8異步編程源碼解讀

2024-08-06 09:43:54

Java 8工具編程

2025-02-06 16:51:30

2022-07-08 14:14:04

并發編程異步編程

2024-02-07 11:44:20

NestJSRxJS異步編程

2011-08-18 13:58:34

iPhone開發NSOperation異步

2017-12-21 15:48:11

JavaCompletable

2023-07-19 08:03:05

Future異步JDK

2021-01-19 05:30:55

C# 8異步流IEnumerable

2024-09-10 09:05:12

SpringREST并發

2023-04-13 07:33:31

Java 8編程工具

2024-01-11 12:14:31

Async線程池任務

2021-12-24 11:25:37

FreeDOS批處理文件Linux
點贊
收藏

51CTO技術棧公眾號

97青娱国产盛宴精品视频| 亚洲欧美色一区| 国产伦精品一区二区三区免| 羞羞答答成人影院www| 成人免费91在线看| 免费在线成人| 91网站在线观看免费| 9色porny自拍视频一区二区| 激情五月俺来也| 亚洲h精品动漫在线观看| 国产午夜精品一区理论片| 日韩欧美一区电影| 草民电影神马电影一区二区| 欧美猛少妇色xxxxx| 欧美亚洲在线日韩| 久久久久欧美| 91丝袜美腿高跟国产极品老师| 成全视频全集| 欧美四级电影在线观看| 免费观看亚洲| 2019av中文字幕| 亚洲精品孕妇| 可以看毛片的网址| 一区二区三区成人在线视频| 国产原厂视频在线观看| 中文字幕欧美日韩精品| 久久99高清| 欧美一区二区三区在线免费观看| 99久久精品一区| 香蕉av在线| 日韩电影在线观看中文字幕 | 狠狠入ady亚洲精品经典电影| 一区二区三区四区久久| 欧美国产国产综合| 成人影院在线看| 久久av中文字幕| 欧美日韩国产免费观看| 欧美爱爱视频免费看| 在线观看国产91| 欧美午夜在线播放| 欧美自拍资源在线| 亚洲午夜久久久久久久久久久 | 色帝国亚洲欧美在线| 欧美激情视频在线| 日韩精品成人一区二区三区| baoyu777.永久免费视频| 日韩精品高清在线观看| 欧美xxxx中国| 青青青国产在线观看| 欧美日本在线一区| 亚洲日本三级| 91动漫在线看| 日韩视频免费直播| 第一社区sis001原创亚洲| 日韩中文字幕在线免费| 欧美福利视频导航| 欧美**vk| 一本大道熟女人妻中文字幕在线| 91精品国产综合久久婷婷香蕉| 日韩精品导航| av免费观看国产| 欧美mv和日韩mv国产网站| 希岛爱理一区二区三区| 人人干人人干人人| 一夜七次郎国产精品亚洲| 欧美一级二区| 青青久草在线| 国产精品盗摄久久久| 国产亚洲精品免费| 唐人社导航福利精品| 欧美日韩亚洲一区二区三区四区| 香蕉久久一区二区不卡无毒影院| 影音先锋欧美激情| 久久精品视频16| 亚洲人精选亚洲人成在线| 日本一不卡视频| 国产激情在线视频| 国产精品制服诱惑| 狠狠色狠狠色综合日日小说| 国产精品密蕾丝视频下载| 亚洲老女人av| 日韩一中文字幕| 成人手机电影网| 欧洲一级精品| 中文字幕日韩一区二区三区| 欧美一区二区三区在线| 黑人一区二区| 国产亚洲依依| 国产伦精品一区二区三区视频孕妇| 亚洲高清免费一级二级三级| 欧洲专线二区三区| 九七影院97影院理论片免费| 欧美激情久久久久| 国产欧美综合在线| 精品三级av在线导航| 成人网18入口| 日韩美女免费线视频| 亚洲精品久久久蜜桃| 香蕉国产成人午夜av影院| 四虎av网址| 日本久久中文字幕| 亚洲国产毛片aaaaa无费看| 91麻豆国产自产在线观看亚洲| 伊人春色在线| 懂色一区二区三区av片| 91麻豆精品国产自产在线 | 在线一区亚洲| 亚洲天堂开心观看| 26uuu另类欧美亚洲曰本| 超碰地址久久| 麻豆电影在线观看| 高清一区二区三区视频| 欧美一区二区视频观看视频| 肉丝袜脚交视频一区二区| 国模精品视频| 欧美亚洲日本一区二区三区| 色综合天天狠天天透天天伊人| 国产午夜精品在线观看| 免费观看久久av| 成人亚洲综合天堂| 一级二级三级欧美| 欧美超级免费视 在线| 亚洲免费三区一区二区| 欧美午夜在线视频| 天堂av中文在线观看| 国产精品涩涩涩视频网站| 91精品国产成人| 日本久久精品电影| 激情综合网av| gogo久久日韩裸体艺术| 一不卡在线视频| 日韩国产精品一区二区三区| 色老头一区二区三区| 一级女性全黄久久生活片免费| 国产精品99免费看| 美女日韩欧美| 97高清视频| 精品无人区一区二区三区 | 99久久99九九99九九九| 色老板视频在线观看| 欧美日韩精品中文字幕一区二区| 伊人久久久久久久久久| 一区二区三区在线免费| 日韩电影网1区2区| 久久综合五月婷婷| 91国产中文字幕| 精品日本美女福利在线观看| 日韩av二区在线播放| 极品束缚调教一区二区网站| yw视频在线观看| 国产黄色激情视频| 国产欧美精品在线| 日韩毛片在线看| 亚洲嫩草精品久久| 日本成人在线视频网站| 亚洲成a人片77777在线播放| 三级福利片在线观看| 爱爱永久免费视频| 亚洲一区高清| 国产精品丝袜白浆摸在线| 国产婷婷97碰碰久久人人蜜臀| 亚洲精品国产精华液| 国内精品视频666| 国产伦精品一区二区三区视频| 福利在线导航136| 日本aⅴ中文| 一级黄色录像免费看| 国产精品久久久久久久美男| 亚洲黄色成人网| 婷婷综合另类小说色区| www.成人网.com| 亚洲制服av| 成人3d精品动漫精品一二三| 久久xxx视频| 黄色网在线看| 一级毛片免费视频| 欧美乱大交xxxxx潮喷l头像| 国产精品一区二区三区精品| 97成人在线视频| 怡红院精品视频| 欧美三区在线观看| 国产精品美女久久久久久久| 国产真实乱对白精彩久久| 欧美在线亚洲综合一区| 爱高潮www亚洲精品| 亚洲欧美一区二区三区| 岛国在线视频免费看| avtt天堂资源网站| 乱人伦xxxx国语对白| 亚洲人一区二区| 91久久久在线| 欧美与黑人午夜性猛交久久久| 亚洲性无码av在线| 精品国精品国产尤物美女| 色屁屁一区二区| 亚洲高清不卡在线| 国产精品美女一区二区三区 | 久久精品国产精品国产精品污| 2019日韩中文字幕mv| 在线免费av导航|