背景介紹
想象這樣一個場景:你可能希望為你的法國客戶提供指定主題的熱點報道。為實現這一功能,你需要向 谷歌或者Twitter的API請求所有語言中針對該主題最熱門的評論,可能還需要依據你的內部算法 對它們的相關性進行排序。之后,你可能還需要使用谷歌的翻譯服務把它們翻譯成法語,甚至 利用谷歌地圖服務定位出評論作者的位置信息,最終將所有這些信息聚集起來,呈現在你的網站上。
典型的“混聚”式應用
在這種“混聚”應用式的應用中,我們的應用可能會有以下兩種需求:
由於我們調用的許多都是外部提供的接口,極有可能出現由於某些外部網絡服務發生響應慢的情況。在這種情況下,我們可能希望依舊能為用戶提供部分信息,比如提供帶問號標記的通用地圖,以文本的方式顯示信息,而不是呆呆地顯示一片空白屏幕,直到地圖服務器返回結果或者超時退出。
要實現類似的服務,你需要與互聯網上的多個Web服務通信。可是,你並不希望因為等待某 些服務的響應,阻塞應用程序的運行,浪費數十億寶貴的CPU時鍾周期。比如,不要因為等待 Facebook的數據,暫停對來自Twitter的數據處理。
以上兩種場景體現了多任務程序設計的另一面。如果你的主要目標是在同一個CPU上執 行幾個松耦合的任務,充分利用CPU的核,讓其足夠忙碌,從而最大化程序的吞吐量,那么你其實真正想做的是避免因為等待遠程服務的返回,或者對數據庫的查詢,而阻塞線程的執行, 浪費寶貴的計算資源,因為這種等待的時間很可能相當長。這時就需要用到異步處理,在Java 5中提供的Future接口和在Java 8 中的新版實現CompletableFuture,就是處理這種情況的利器。
Feature接口
Future接口在Java 5中被引入,設計初衷是對將來某個時刻會發生的結果進行建模。它建模 了一種異步計算,返回一個執行運算結果的引用,當運算結束后,這個引用被返回給調用方。在 Future中觸發那些潛在耗時的操作把調用線程解放出來,讓它能繼續執行其他有價值的工作, 不再需要呆呆等待耗時的操作完成。
Feature接口和Tread的區別
Future的優點是它比 更底層的Thread更易用。要使用Future,通常你只需要將耗時的操作封裝在一個Callable對 象中,再將它提交給ExecutorService,就萬事大吉了。
Feature接口示例
下面是一個Feature的demo示例:
public void testFeature() {
//創建Executor- Service,通 過它你可以 向線程池提 交任務
ExecutorService executor = Executors.newCachedThreadPool();
//向Executor- Service提交一個 Callable對象
final Future<Double> futureRate = executor.submit(new Callable<Double>() {
public Double call() {
//以異步方式在新的線程中執行耗時的操作
return doSomeLongComputation();
}
});
//異步操作進行的同時你可以做其他的事情
doSomethingElse();
try {
//獲取異步操作的結果,如果最終被阻塞,無法得到結果,那么在最多等待1秒鍾之后退出
Double result = future.get(1, TimeUnit.SECONDS);
} catch (ExecutionException e) {
// 計算拋出一個異常
e.printStackTrace();
} catch (InterruptedException ie) { // 當前線程在等待過程中被中斷
} catch (TimeoutException te) { // 在Future對象完成之前超過已過期
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
使用Future以異步方式執行長時間的操作
如上圖所示,這種編程方式讓你的線程可以在ExecutorService以並發方式調 用另一個線程執行耗時操作的同時,去執行一些其他的任務。接着,如果你已經運行到沒有異步 操作的結果就無法繼續任何有意義的工作時,可以調用它的get方法去獲取操作的結果。如果操 作已經完成,該方法會立刻返回操作的結果,否則它會阻塞你的線程,直到操作完成,返回相應 的結果。如果該長時間運行的操作永遠不返回了會怎樣?為了處理這種可能性,雖然Future提供了一個無需任何參數的get方法,我們還是推薦大家使用重 載版本的get方法,它接受一個超時的參數,通過它,你可以定義你的線程等待Future結果的最 長時間,從而無需永無止境的等待下去。
Feature接口的局限性
雖然Feature接口提供了方法來檢測異步計算是否已經結束(使用 isDone方法),等待異步操作結束,以及獲取計算的結果。但是這些特性還不足以讓你編寫簡潔的並發代碼。
我們可能還需要更多的特性來幫助我們寫出更好異步代碼,如:
將兩個異步計算合並為一個——這兩個異步計算之間相互獨立,同時第二個又依賴於第 一個的結果。
等待Future集合中的所有任務都完成。
僅等待Future集合中最快結束的任務完成(有可能因為它們試圖通過不同的方式計算同一個值),並返回它的結果。
通過編程方式完成一個Future任務的執行(即以手工設定異步操作結果的方式)。
應對Future的完成事件(即當Future的完成事件發生時會收到通知,並能使用Future
計算的結果進行下一步的操作,不只是簡單地阻塞等待操作的結果)。
下一節我們將介紹新的CompletableFuture類(它實現了Future接口)如何利用Java 8 的新特性以更直觀的方式將上述需求都變為可能。
————————————————
版權聲明:本文為CSDN博主「棟先生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/wangdong5678999/article/details/81837387