正確使用Java?CompletableFuture對象的方法
1 什么是 CompletableFuture?
CompletableFuture 是 Java 8 引入的一個強大的異步編程工具。允許以聲明式的方式處理異步任務(wù)的結(jié)果,避免了傳統(tǒng)回調(diào)和手動管理線程的復(fù)雜性。
CompletableFuture 可以組合和鏈?zhǔn)秸{(diào)用,高效地利用多核處理器的能力,并且減少了傳統(tǒng)并發(fā)編程中常見的競態(tài)條件和死鎖等問題。
在日常開發(fā)中,經(jīng)常需要處理那些可能耗時的任務(wù),比如網(wǎng)絡(luò)請求、數(shù)據(jù)庫查詢或者復(fù)雜的計算。使用 CompletableFuture,可以告訴程序如何在后臺執(zhí)行這些任務(wù),然后在任務(wù)完成后執(zhí)行特定的操作。
可以想象一下,CompletableFuture 就像是一條可以穿越時間的信使,你可以把一項任務(wù)托付給它,然后繼續(xù)做其他事情。當(dāng)任務(wù)完成時,它會及時將結(jié)果送回來,讓你可以立即處理。這樣,你就不必在等待任務(wù)完成的過程中浪費時間,而是可以更高效地利用自己的資源。
2 如何正確使用 CompletableFuture 對象?
CompletableFuture 可以以一種非阻塞的方式執(zhí)行異步任務(wù),并能夠在任務(wù)完成后立即得到通知。通過鏈?zhǔn)秸{(diào)用的方式,可以很方便地組合多個異步操作,處理它們的結(jié)果或者異常。
通過 CompletableFuture.supplyAsync() 方法創(chuàng)建一個 CompletableFuture 對象,并指定一個需要異步執(zhí)行的任務(wù):
// Supplier 函數(shù)會在一個新的線程上異步執(zhí)行
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模擬一個耗時操作,如從數(shù)據(jù)庫中讀取數(shù)據(jù)
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "異步任務(wù)完成";
});
通過在 CompletableFuture 上添加一些操作,比如處理任務(wù)的結(jié)果或者處理任務(wù)執(zhí)行過程中可能發(fā)生的異常:
// thenAccept()方法接收一個 Consumer 函數(shù)
future.thenAccept(result -> {
System.out.println("任務(wù)完成,結(jié)果為:" + result);
}).exceptionally(ex -> {
System.out.println("任務(wù)出現(xiàn)異常:" + ex.getMessage());
return null;
});
3 如何結(jié)合回調(diào)函數(shù)處理異步任務(wù)結(jié)果?
結(jié)合回調(diào)函數(shù)處理異步任務(wù)結(jié)果的過程可以比作在等待一份重要的快遞時安排一個通知服務(wù)。這個通知服務(wù)就是回調(diào)函數(shù),它會在快遞送達時通知你,或者在處理完成后執(zhí)行特定的操作。
在 Java 的 CompletableFuture 中,這種模式可以通過 supplyAsync() 、thenApply()、thenAccept() 和 handle() 方法來實現(xiàn)。
創(chuàng)建一個異步任務(wù)時,使用 CompletableFuture.supplyAsync() 可以啟動一個任務(wù),這個任務(wù)在后臺線程中執(zhí)行,直到它完成。假設(shè)有一個任務(wù)需要從遠(yuǎn)程服務(wù)器獲取數(shù)據(jù):
// supplyAsync() 方法接收一個 Supplier 函數(shù),這個函數(shù)會在后臺線程中運行,并返回一個結(jié)果
// 結(jié)果會被封裝在 CompletableFuture 對象中,等待進一步處理
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模擬從遠(yuǎn)程服務(wù)器獲取數(shù)據(jù)
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "數(shù)據(jù)已成功獲取";
});
使用 thenApply() 方法,可以在異步任務(wù)完成后,對結(jié)果進行轉(zhuǎn)換。這個方法接收一個 Function 函數(shù),這個函數(shù)會接收任務(wù)的結(jié)果,并返回一個新結(jié)果。比如,將獲取的數(shù)據(jù)進行處理:
// thenApply() 方法將原始數(shù)據(jù)轉(zhuǎn)換為大寫形式
// 處理后的結(jié)果會成為新的 CompletableFuture 對象的結(jié)果
CompletableFuture<String> processedFuture = future.thenApply(result -> {
// 對結(jié)果進行處理
return result.toUpperCase();
});
為了執(zhí)行一個操作而不關(guān)心處理的結(jié)果,可以使用 thenAccept() 方法。這個方法接收一個 Consumer 函數(shù),它處理任務(wù)完成時的結(jié)果,可以在異步任務(wù)完成時執(zhí)行一些操作,比如日志記錄或通知用戶。例如,將結(jié)果打印到控制臺:
// 在任務(wù)完成后會調(diào)用傳入的 Consumer 函數(shù),并將結(jié)果傳遞給它
future.thenAccept(result -> {
System.out.println("任務(wù)完成,結(jié)果是:" + result);
});
在任務(wù)執(zhí)行過程中,可能會遇到異常。handle() 方法可以用來處理這些異常,它接收一個 BiFunction 函數(shù),這個函數(shù)接收結(jié)果和異常(如果有的話),并返回一個處理后的結(jié)果。例如:
// handle() 方法檢查是否有異常發(fā)生
// 如果有異常,它會處理異常并返回一個默認(rèn)的結(jié)果
// 如果沒有異常,它會處理正常的結(jié)果
CompletableFuture<String> handledFuture = future.handle((result, ex) -> {
if (ex != null) {
// 處理異常
System.out.println("任務(wù)發(fā)生錯誤:" + ex.getMessage());
return "錯誤處理結(jié)果";
}
// 處理正常結(jié)果
return result.toLowerCase();
});
對于這四種回調(diào)函數(shù),可以使得異步任務(wù)的結(jié)果處理變得靈活而強大。通過結(jié)合使用不同的回調(diào)函數(shù),可以對異步任務(wù)的結(jié)果進行多種操作,保證程序在處理復(fù)雜任務(wù)時仍然保持清晰和高效。
4 如何組合并處理多個 CompletableFuture?
組合和處理多個 CompletableFuture 可以讓并發(fā)任務(wù)變得更加靈活和高效。設(shè)想有多個任務(wù)需要并行執(zhí)行,然后將它們的結(jié)果結(jié)合起來進行進一步處理。
在進行組合時,最基本的方法之一是將多個 CompletableFuture 的結(jié)果合并。比如,有兩個任務(wù)需要并行完成,獲取兩個不同的數(shù)據(jù)源,然后將這兩個結(jié)果結(jié)合起來。
可以使用 thenCombine() 方法,它接收兩個 CompletableFuture 和一個合并函數(shù),兩個 CompletableFuture 必須在相同的線程池中執(zhí)行。
假設(shè)有兩個任務(wù)分別從不同的 API 獲取數(shù)據(jù):
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
// 模擬從第一個 API 獲取數(shù)據(jù)
return "數(shù)據(jù)1";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 模擬從第二個 API 獲取數(shù)據(jù)
return "數(shù)據(jù)2";
});為了將這兩個結(jié)果結(jié)合起來,可以使用 thenCombine():
// thenCombine() 方法接收兩個 CompletableFuture 和一個函數(shù),這個函數(shù)將兩個任務(wù)的結(jié)果合并成一個結(jié)果
// 最終的結(jié)果是將兩個字符串連接在一起
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
// 將兩個結(jié)果結(jié)合成一個
return result1 + " 和 " + result2;
});
另一個有用的方法是 allOf()方法。當(dāng)有多個任務(wù)需要并行執(zhí)行,并且在所有任務(wù)完成后執(zhí)行某個操作時,allOf() 非常有用。它接收一個 CompletableFuture 數(shù)組,并在所有這些 CompletableFuture 完成時觸發(fā)??梢杂脕淼却鄠€異步任務(wù)完成,然后執(zhí)行某個操作:
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2);
要獲取所有任務(wù)的結(jié)果,可以在 allOf() 的結(jié)果上添加一個回調(diào)函數(shù):
// thenRun() 方法會在所有任務(wù)完成后執(zhí)行,它不需要處理結(jié)果,只是執(zhí)行某個操作
allOfFuture.thenRun(() -> {
// 處理所有任務(wù)完成后的操作
try {
String result1 = future1.get();
String result2 = future2.get();
System.out.println("任務(wù)1的結(jié)果: " + result1);
System.out.println("任務(wù)2的結(jié)果: " + result2);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
});
如果有任務(wù)依賴于另一個任務(wù)的結(jié)果,可以使用 thenCompose()方法。這種情況下,第二個任務(wù)會在第一個任務(wù)完成后開始執(zhí)行。thenCompose() 方法接收一個返回 CompletableFuture 的函數(shù),然后將這兩個 CompletableFuture 鏈接起來:
CompletableFuture<String> future3 = future1.thenCompose(result1 -> {
// 使用第一個任務(wù)的結(jié)果來創(chuàng)建新的 CompletableFuture
return CompletableFuture.supplyAsync(() -> result1 + " 處理完成");
});
對于這些方法來說,它們?yōu)樘幚矶鄠€異步任務(wù)提供了強大的工具,使得并發(fā)編程更加高效和靈活。通過合理使用這些方法,可以實現(xiàn)復(fù)雜的異步任務(wù)組合和處理邏輯,確保程序的高效執(zhí)行。
到此這篇關(guān)于Java CompletableFuture深入解析的文章就介紹到這了,更多相關(guān)Java CompletableFuture內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java CompletableFuture之異步執(zhí)行、鏈?zhǔn)秸{(diào)用、組合多個Future、異常處理和超時控制等詳解
- Java CompletableFuture如何實現(xiàn)超時功能
- Java使用CompletableFuture實現(xiàn)異步編程
- Java8 CompletableFuture異步編程解讀
- java使用CompletableFuture分批處理任務(wù)實現(xiàn)
- Java中的CompletableFuture基本用法
- Java中的CompletableFuture原理與用法
- Java中的CompletableFuture異步編程詳解
- Java中的CompletableFuture詳解
相關(guān)文章
servlet之session工作原理簡介_動力節(jié)點Java學(xué)院整理
這篇文章主要介紹了servlet之session工作原理簡介,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-07-07
詳解spring中使用Elasticsearch的代碼實現(xiàn)
本篇文章主要介紹了詳解spring中使用Elasticsearch的代碼實現(xiàn),具有一定的參考價值,有興趣的可以了解一下2017-05-05
Spring Boot配置application.yml及根據(jù)application.yml選擇啟動配置的操作
Spring Boot中可以選擇applicant.properties 作為配置文件,也可以通過在application.yml中進行配置,讓Spring Boot根據(jù)你的選擇進行加載啟動配置文件,本文給大家介紹Spring Boot配置application.yml及根據(jù)application.yml選擇啟動配置的操作方法,感興趣的朋友一起看看吧2023-10-10
java如何實現(xiàn)遞歸刪除樹形數(shù)據(jù)的任一個節(jié)點
文章講述了在Java中實現(xiàn)遞歸刪除樹形數(shù)據(jù)的任一個節(jié)點時需要注意的三個點,包括刪除的節(jié)點包含子節(jié)點、刪除子節(jié)點和其他子節(jié)點刪除的節(jié)點不包含子節(jié)點、以及該父節(jié)點變成葉子節(jié)點,此外,文章還提到這兩件事包含在同一件事務(wù)中2024-12-12
SpringBoot啟動訪問localhost:8080報錯404的解決操作
這篇文章主要介紹了SpringBoot啟動訪問localhost:8080報錯404的解決操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10
IDEA中Maven報錯Cannot resolve xxx的解決方法匯總(親測有效)
在IDEA中的pom文件中添加了依賴,并且正確加載了相應(yīng)依賴,pom文件沒有報紅,看起來像是把所有依賴庫全部加載進來了,但是代碼中使用依賴的類庫使報紅,本文給大家介紹了IDEA中Maven報錯Cannot resolve xxx的解決方法匯總,需要的朋友可以參考下2024-06-06

