激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - Java8 使用CompletableFuture 構(gòu)建異步應(yīng)用方式

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

2022-03-11 01:00小小工匠 Java教程

這篇文章主要介紹了Java8 使用CompletableFuture 構(gòu)建異步應(yīng)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

概述

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

這個(gè)過(guò)程中,會(huì)學(xué)到幾個(gè)重要的技能。

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

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

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

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

 

同步API VS 異步API

同步API

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

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

異步API

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

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

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

 

同步的困擾

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

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

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

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

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

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

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

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

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

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


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

 

實(shí)現(xiàn)異步API

將同步方法改為異步方法

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

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

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

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

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

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

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

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

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

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

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

【使用異步的API】

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

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

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

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

輸出

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

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

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

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

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

處理異常錯(cuò)誤

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

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

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

不過(guò),也因?yàn)槿绱?,你不?huì)有機(jī)會(huì)發(fā)現(xiàn)計(jì)算商品價(jià)格的線程內(nèi)到底發(fā)生了什么問(wèn)題才引發(fā)了這樣的失效。

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

代碼如下

【拋出CompletableFuture內(nèi)的異常】

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

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

所以,舉例來(lái)說(shuō),如果該方法拋出了一個(gè)運(yùn)行時(shí)異常“product not available”,客戶端就會(huì)得到像下面這樣一段 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)

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

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://artisan.blog.csdn.net/article/details/115450838

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久久久久亚洲国产精品 | 中国免费一级毛片 | 黄色a级片视频 | 亚洲91网 | www.91sp| 一级在线观看 | 亚洲人成网在线观看 | 日本欧美一区二区三区视频麻豆 | 欧美伦交 | 成人性生活视频 | 欧美福利视频一区二区三区 | 最新se94se在线欧美 | 91精品国产91久久久久久吃药 | 久久亚洲精品视频 | 杏美月av | 欧美成人性色 | 成人一级黄色片 | 国产高潮好爽受不了了夜色 | 一级黄色大片在线观看 | 中国免费一级毛片 | 国产日韩一区二区三区在线观看 | 操毛片| 性生活视频软件 | 黄色免费大片 | 精品国产一区二区三区久久久 | 欧美日韩在线播放 | 九一免费在线观看 | 国产视频aa | 国产精品hd免费观看 | 91网视频在线观看 | 日韩激情| 中国美女一级黄色大片 | 国产一区精品在线观看 | 欧美城网站地址 | 手机在线看片国产 | 色av综合在线 | 毛片118极品美女写真 | 性片网站 | 欧美女人天堂 | 亚洲成人欧美在线 | 精品日韩欧美 |