最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java8 使用CompletableFuture 構(gòu)建異步應(yīng)用方式

 更新時間:2021年11月04日 11:34:51   作者:小小工匠  
這篇文章主要介紹了Java8 使用CompletableFuture 構(gòu)建異步應(yīng)用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

概述

為了展示 CompletableFuture 的強大特性, 創(chuàng)建一個名為 best-price-finder 的應(yīng)用,它會查詢多個在線商店,依據(jù)給定的產(chǎn)品或服務(wù)找出最低的價格。

這個過程中,會學(xué)到幾個重要的技能。

  • 如何提供異步API
  • 如何讓你使用了同步API的代碼變?yōu)榉亲枞a

我們將共同學(xué)習(xí)如何使用流水線將兩個接續(xù)的異步操作合并為一個異步計算操作。 比如,在線商店返回了你想要購買的商品的原始價格,并附帶著一個折扣代碼——最終,要計算出該商品的實際價格,你不得不訪問第二個遠(yuǎn)程折扣服務(wù),查詢該折扣代碼對應(yīng)的折扣比率

  • 如何以響應(yīng)式的方式處理異步操作的完成事件,以及隨著各個商品返回它的商品價格,最佳價格查詢器如何持續(xù)的更新每種商品的最佳推薦,而不是等待所有的商店都返回他們各自的價格(這種方式存在著一定的風(fēng)險,一旦某家商店的服務(wù)中斷,用戶可能遭遇白屏)。

在這里插入圖片描述

同步API VS 異步API

同步API

是對傳統(tǒng)方法的另一種稱呼:你調(diào)用了某個方法,調(diào)用方在被調(diào)用方運行的過程中會等待,被調(diào)用方運行結(jié)束返回,調(diào)用方取的了被調(diào)用方的返回值并繼續(xù)運行。

即使調(diào)用方和被調(diào)用方在不同的線程中運行,調(diào)用方還是需要等被調(diào)用方結(jié)束運行,這就是 阻塞式調(diào)用。

異步API

與同步API相反,異步API會直接返回,或者至少在被調(diào)用方計算完成之前,將它剩余的計算任務(wù)交給另一個線程去做,該線程和調(diào)用方是異步的。 這就是非阻塞調(diào)用。

執(zhí)行剩余的計算任務(wù)的線程將他的計算結(jié)果返回給調(diào)用方。 返回的方式要么通過回調(diào)函數(shù),要么由調(diào)用方再此執(zhí)行一個“等待,指導(dǎo)計算完成”的方法調(diào)用。

同步的困擾

為了實現(xiàn)最佳價格查詢器應(yīng)用,讓我們從每個商店都應(yīng)該提供的API定義入手。

首先,商店應(yīng)該聲明依據(jù)指定產(chǎn)品名稱返回價格的方法:

public class Shop {
	public double getPrice(String product) {
	// TODO
	}
}

該方法的內(nèi)部實現(xiàn)會查詢商店的數(shù)據(jù)庫,但也有可能執(zhí)行一些其他耗時的任務(wù),比如聯(lián)系其他外部服務(wù)。

用 delay 方法模擬這些長期運行的方法的執(zhí)行,模擬執(zhí)行1S ,方法聲明如下。

public static void delay() {
	try {
		Thread.sleep(1000L);
	} catch (InterruptedException e) {
		throw new RuntimeException(e);
	}
}

getPrice 方法會調(diào)用 delay 方法,并返回一個隨機計算的值

public double getPrice(String product) {
	return calculatePrice(product);
}
private double calculatePrice(String product) {
	delay();
	return random.nextDouble() * product.charAt(0) + product.charAt(1);
}

很明顯,這個API的使用者(這個例子中為最佳價格查詢器)調(diào)用該方法時,它依舊會被阻塞。為等待同步事件完成而等待1S,這是無法接受的,尤其是考慮到最佳價格查詢器對網(wǎng)絡(luò)中的所有商店都要重復(fù)這種操作。

接下來我們會了解如何以異步方式使用同步API解決這個問題。但是,出于學(xué)習(xí)如何設(shè)計異步API的考慮, 你希望以異步API的方式重寫這段代碼, 假裝我們還在深受這一困難的煩惱,如何以異步API的方式重寫這段代碼,讓用戶更流暢地訪問呢?


在這里插入圖片描述

實現(xiàn)異步API

將同步方法改為異步方法

為了實現(xiàn)這個目標(biāo),你首先需要將 getPrice 轉(zhuǎn)換為 getPriceAsync 方法,并修改它的返回值:

public Future<Double> getPriceAsync(String product) { ... }

我們知道 ,Java 5引入了 java.util.concurrent.Future 接口表示一個異步計算(即調(diào)用線程可以繼續(xù)運行,不會因為調(diào)用方法而阻塞)的結(jié)果 。

這意味著 Future 是一個暫時還不可知值的處理器,這個值在計算完成后,可以通過調(diào)用它的 get 方法取得。因為這樣的設(shè)計, getPriceAsync 方法才能立刻返回,給調(diào)用線程一個機會,能在同一時間去執(zhí)行其他有價值的計算任務(wù)。

新的 CompletableFuture 類提供了大量的方法,讓我們有機會以多種可能的方式輕松地實現(xiàn)這個方法,比如下面就是這樣一段實現(xiàn)代碼

【getPriceAsync方法的實現(xiàn)】

在這里插入圖片描述

在這段代碼中,創(chuàng)建了一個代表異步計算的 CompletableFuture 對象實例,它在計算完成時會包含計算的結(jié)果。

接著,調(diào)用 fork 創(chuàng)建了另一個線程去執(zhí)行實際的價格計算工作,不等該耗時計算任務(wù)結(jié)束,直接返回一個 Future 實例。

當(dāng)請求的產(chǎn)品價格最終計算得出時,你可以使用它的 complete 方法,結(jié)束completableFuture 對象的運行,并設(shè)置變量的值。

很顯然,這個新版 Future 的名稱也解釋了它所具有的特性。使用這個API的客戶端,可以通過下面的這段代碼對其進行調(diào)用。

【使用異步的API】

在這里插入圖片描述

我們看到這段代碼中,客戶向商店查詢了某種商品的價格。由于商?提供了異步API,該次調(diào)用立刻返回了一個 Future 對象,通過該對象客戶可以在將來的某個時刻取得商品的價格。

這種方式下,客戶在進行商品價格查詢的同時,還能執(zhí)行一些其他的任務(wù),比如查詢其他家商店中商品的價格,不會呆呆的阻塞在那里等待第一家商店返回請求的結(jié)果。

最后,如果所有有意義的工作都已經(jīng)完成,客戶所有要執(zhí)行的工作都依賴于商品價格時,再調(diào)用 Future 的 get 方法。執(zhí)行了這個操作后,客戶要么獲得 Future 中封裝的值(如果異步任務(wù)已經(jīng)完成),要么發(fā)生阻塞,直到該異步任務(wù)完成,期望的值能夠訪問。

輸出

在這里插入圖片描述

你一定已經(jīng)發(fā)現(xiàn) getPriceAsync 方法的調(diào)用返回遠(yuǎn)遠(yuǎn)早于最終價格計算完成的時間。

我們有可能避免發(fā)生客戶端被住阻塞的風(fēng)險。實際上這非常簡單, Future 執(zhí)行完畢可以發(fā)出一個通知,僅在計算結(jié)果可用時執(zhí)行一個由Lambda表達(dá)式或者方法引用定義的回
調(diào)函數(shù)。

不過,我們當(dāng)下不會對此進行討論,現(xiàn)在我們要解決的是另一個問題:如何正確地管理
異步任務(wù)執(zhí)行過程中可能出現(xiàn)的錯誤。

在這里插入圖片描述

處理異常錯誤

如果沒有意外,我們目前開發(fā)的代碼工作得很正常。但是,如果價格計算過程中產(chǎn)生了錯誤會怎樣呢?非常不幸,這種情況下你會得到一個相當(dāng)糟糕的結(jié)果:用于提示錯誤的異常會被限制在試圖計算商品價格的當(dāng)前線程的范圍內(nèi),最終會殺死該線程,而這會導(dǎo)致等待 get 方法返回結(jié)果的客戶端永久的被阻塞。

客戶端可以使用重載版本的 get 方法,它使用一個超時參數(shù)來避免發(fā)生這樣的情況。這是一種值得推薦的做法,你應(yīng)該盡量在你的代碼中添加超時判斷斷的邏輯,避免發(fā)生類似的問題。

使用這種方法至少能防止程序永遠(yuǎn)的等待下去,超時發(fā)生時,程序會得到通知發(fā)生了 Timeout-Exception 。

不過,也因為如此,你不會有機會發(fā)現(xiàn)計算商品價格的線程內(nèi)到底發(fā)生了什么問題才引發(fā)了這樣的失效。

為了讓客戶端能了解商店無法提供請求商品價格的原因,你需要使用
CompletableFuture 的 completeExceptionally 方法將導(dǎo)致 CompletableFuture 內(nèi)發(fā)生問題的異常拋出。

代碼如下

【拋出CompletableFuture內(nèi)的異?!?/strong>

1

客戶端現(xiàn)在會收到一個 ExecutionException 異常,該異常接收了一個包含失敗原因的Exception 參數(shù),即價格計算方法最初拋出的異常。

所以,舉例來說,如果該方法拋出了一個運行時異?!皃roduct not available”,客戶端就會得到像下面這樣一段 ExecutionException :

java.util.concurrent.ExecutionException: java.lang.RuntimeException: product
not available at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2237)
at lambdasinaction.chap11.AsyncShopClient.main(AsyncShopClient.java:14)
... 5 more
Caused by: java.lang.RuntimeException: product not available
at lambdasinaction.chap11.AsyncShop.calculatePrice(AsyncShop.java:36)
at lambdasinaction.chap11.AsyncShop.lambda$getPrice$0(AsyncShop.java:23)
at lambdasinaction.chap11.AsyncShop$$Lambda$1/24071475.run(Unknown Source)
at java.lang.Thread.run(Thread.java:744)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot+docker環(huán)境變量配置詳解

    SpringBoot+docker環(huán)境變量配置詳解

    這篇文章主要介紹了SpringBoot+docker環(huán)境變量配置詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Java輸入三個整數(shù)并把他們由小到大輸出(x,y,z)

    Java輸入三個整數(shù)并把他們由小到大輸出(x,y,z)

    這篇文章主要介紹了輸入三個整數(shù)x,y,z,請把這三個數(shù)由小到大輸出,需要的朋友可以參考下
    2017-02-02
  • Java反射技術(shù)詳解

    Java反射技術(shù)詳解

    這篇文章主要結(jié)合實例形式分析了介紹了Java反射技術(shù),小編覺得這篇文章寫的還不錯,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-11-11
  • java中四種操作xml方式的比較

    java中四種操作xml方式的比較

    本文主要介紹了java中四種操作xml的方式并對它們進行比較分析。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • SpringBoot如何通過Map實現(xiàn)策略模式

    SpringBoot如何通過Map實現(xiàn)策略模式

    策略模式是一種行為設(shè)計模式,它允許在運行時選擇算法的行為,在Spring框架中,我們可以利用@Resource注解和Map集合來優(yōu)雅地實現(xiàn)策略模式,這篇文章主要介紹了SpringBoot如何通過Map實現(xiàn)策略模式,需要的朋友可以參考下
    2025-03-03
  • spring?boot學(xué)習(xí)筆記之操作ActiveMQ指南

    spring?boot學(xué)習(xí)筆記之操作ActiveMQ指南

    ActiveMQ是一種開源的基于JMS規(guī)范的一種消息中間件的實現(xiàn),ActiveMQ的設(shè)計目標(biāo)是提供標(biāo)準(zhǔn)的,面向消息的,能夠跨越多語言和多系統(tǒng)的應(yīng)用集成消息通信中間件,這篇文章主要給大家介紹了關(guān)于spring?boot學(xué)習(xí)筆記之操作ActiveMQ指南的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • Java中equals()方法實例詳解

    Java中equals()方法實例詳解

    equals方法是java.lang.Object類的方法,下面這篇文章主要給大家介紹了關(guān)于Java中equals()方法的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-12-12
  • drools中then部分的寫法(推薦)

    drools中then部分的寫法(推薦)

    本文介紹一下drools中then部分的寫法,以及一些內(nèi)置的方法,比如insert/delete/modify等等。同時也介紹一下rule的繼承,和在when中實現(xiàn)if else if?等操作,感興趣的朋友跟隨小編一起看看吧
    2022-05-05
  • SpringMVC數(shù)據(jù)校驗+VO++脫敏實戰(zhàn)指南

    SpringMVC數(shù)據(jù)校驗+VO++脫敏實戰(zhàn)指南

    SpringMVC通過整合BeanValidation規(guī)范,提供靈活的數(shù)據(jù)校驗機制,核心步驟包括添加校驗注解、使用@Valid觸發(fā)校驗、捕獲錯誤,可選擴展,文章還介紹了全局異常處理、自定義校驗注解以及VO層的使用,感興趣的朋友一起看看吧
    2025-03-03
  • Java中的JWT使用詳解

    Java中的JWT使用詳解

    這篇文章主要介紹了Java中的JWT使用詳解,JWT是一個開放標(biāo)準(zhǔn)(rfc7519),它定義了一種緊湊的、自包含的方式,用于在各方之間以JSON對象安全地傳輸信息,需要的朋友可以參考下
    2023-08-08

最新評論

景谷| 芦溪县| 仁怀市| 大渡口区| 浠水县| 高雄市| 郑州市| 太原市| 武宣县| 张家口市| 赣州市| 顺昌县| 太保市| 扶绥县| 龙川县| 武山县| 高安市| 老河口市| 吉水县| 孟州市| 息烽县| 西林县| 宜阳县| 瑞昌市| 南郑县| 类乌齐县| 蓬溪县| 景德镇市| 绥宁县| 荆州市| 锡林郭勒盟| 江西省| 镇沅| 旺苍县| 巴彦县| 资阳市| 连城县| 云安县| 洮南市| 灵武市| 曲阳县|