1. 共同點(diǎn)
異步編程: 這三種機(jī)制都用于處理異步操作且预,即在不阻塞當(dāng)前線程的情況下執(zhí)行任務(wù),并在任務(wù)完成后通知結(jié)果烙无。
-
結(jié)果獲确嫘场: 所有三種機(jī)制都提供獲取異步操作結(jié)果的方法,例如:
Future.get()
CompletionStage.toCompletableFuture().join()
CompletableFuture.join()
-
錯(cuò)誤處理: 所有三種機(jī)制都提供處理異步操作中發(fā)生的異常的方法截酷,例如:
-
Future.get()
可能會(huì)拋出異常涮拗。 -
CompletionStage.exceptionally()
和CompletableFuture.exceptionally()
可以捕獲異常。
-
2. 優(yōu)勢(shì)
Future
-
簡(jiǎn)單易用:
Future
是 Java 1.5 中引入的迂苛,相對(duì)來(lái)說(shuō)比較簡(jiǎn)單三热,易于理解。 -
基礎(chǔ)機(jī)制:
Future
是異步操作的核心三幻,其他的機(jī)制就漾,例如CompletionStage
和CompletableFuture
都是基于Future
實(shí)現(xiàn)的。
CompletionStage
-
靈活的組合和處理:
CompletionStage
提供了豐富的組合方法念搬,例如thenApply
抑堡、thenAccept
、thenCompose
等锁蠕,可以方便地將多個(gè)異步操作進(jìn)行組合和處理夷野,以滿足復(fù)雜業(yè)務(wù)需求。 -
鏈?zhǔn)秸{(diào)用:
CompletionStage
支持鏈?zhǔn)秸{(diào)用荣倾,可以將多個(gè)異步操作連接起來(lái)悯搔,形成一個(gè)完整的異步操作流程,簡(jiǎn)化代碼編寫(xiě)舌仍。
CompletableFuture
-
功能更豐富:
CompletableFuture
提供了更加豐富的方法妒貌,除了CompletionStage
接口中定義的方法之外,還提供了complete
铸豁、completeExceptionally
灌曙、join
等方法,可以更加靈活地控制異步操作节芥。 -
高效:
CompletableFuture
的實(shí)現(xiàn)更加高效在刺,因?yàn)樗褂昧艘恍﹥?yōu)化技術(shù)逆害,例如延遲初始化和緩存。
3. 示例代碼
3.1蚣驼、Future
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class FutureExample {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(() -> {
// 模擬耗時(shí)操作
Thread.sleep(1000);
return "Hello, Future!";
});
// 獲取結(jié)果
String result = future.get();
System.out.println("Result: " + result);
executor.shutdown();
}
}
3.2魄幕、CompletionStage
import java.util.concurrent.CompletableFuture;
public class CompletionStageExample {
public static void main(String[] args) {
CompletionStage<String> future = CompletableFuture.supplyAsync(() -> {
// 模擬耗時(shí)操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello, CompletionStage!";
});
future.thenApply(s -> s.toUpperCase())
.thenAccept(System.out::println)
.exceptionally(throwable -> {
System.err.println("Error occurred: " + throwable.getMessage());
return null;
});
}
}
進(jìn)階用法
3.3、颖杏、將兩個(gè) CompletionStage 的結(jié)果合并在一起
我們以一個(gè)常見(jiàn)的場(chǎng)景 — 網(wǎng)絡(luò)請(qǐng)求為例纯陨,來(lái)說(shuō)明 CompletionStage 的鏈?zhǔn)秸{(diào)用如何簡(jiǎn)化代碼:
場(chǎng)景描述:
假設(shè)你需要從兩個(gè)不同的 API 獲取數(shù)據(jù),然后將這兩個(gè)數(shù)據(jù)進(jìn)行合并處理留储,最后將合并后的數(shù)據(jù)展示給用戶(hù)翼抠。
傳統(tǒng)方法:
// 使用傳統(tǒng)的回調(diào)方式
public void fetchAndProcessData() {
// 第一個(gè) API 請(qǐng)求
api1.fetch(new Callback<Data1>() {
@Override
public void onSuccess(Data1 data1) {
// 第二個(gè) API 請(qǐng)求
api2.fetch(new Callback<Data2>() {
@Override
public void onSuccess(Data2 data2) {
// 合并數(shù)據(jù)
ProcessedData processedData = processData(data1, data2);
// 展示結(jié)果
showResult(processedData);
}
@Override
public void onFailure(Throwable throwable) {
// 處理錯(cuò)誤
handleError(throwable);
}
});
}
@Override
public void onFailure(Throwable throwable) {
// 處理錯(cuò)誤
handleError(throwable);
}
});
}
使用 CompletionStage 的方法:
// 使用 CompletionStage 進(jìn)行鏈?zhǔn)秸{(diào)用
public void fetchAndProcessData() {
CompletionStage<Data1> data1Future = api1.fetch();
CompletionStage<Data2> data2Future = api2.fetch();
data1Future.thenCombine(data2Future, this::processData) // 合并數(shù)據(jù)
.thenAccept(this::showResult) // 展示結(jié)果
.exceptionally(this::handleError); // 處理錯(cuò)誤
}
private ProcessedData processData(Data1 data1, Data2 data2) {
// 合并數(shù)據(jù)邏輯
// ...
return processedData;
}
private void showResult(ProcessedData processedData) {
// 展示結(jié)果邏輯
// ...
}
private Throwable handleError(Throwable throwable) {
// 處理錯(cuò)誤邏輯
// ...
return throwable;
}
3.4、將 CompletionStage 的結(jié)果作為另一個(gè) CompletionStage 的輸入
示例:
假設(shè)我們有一個(gè)數(shù)據(jù)庫(kù)查詢(xún)操作获讳,需要先獲取用戶(hù) ID阴颖,然后再根據(jù)用戶(hù) ID 獲取用戶(hù)信息。我們可以使用 CompletionStage 的 thenCompose 方法來(lái)實(shí)現(xiàn)這個(gè)操作:
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
public class CompletionStageChain {
public static void main(String[] args) {
// Step 1: 獲取用戶(hù)信息
CompletableFuture<String> user = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "用戶(hù)A";
});
// Step 2: 使用用戶(hù)信息獲取訂單列表
Function<String, CompletableFuture<String>> getOrders = userStr -> CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "訂單列表:" + userStr + "的訂單信息";
});
// Step 3: 將用戶(hù)信息和訂單列表拼接在一起
Function<String, String> joinUserAndOrders = orders -> "用戶(hù)信息:" + user.join() + "\n" + orders;
// 將多個(gè) CompletionStage 連接起來(lái)
user.thenCompose(getOrders)
.thenApply(joinUserAndOrders)
.thenAccept(System.out::println)
.exceptionally(throwable -> {
System.err.println("Error occurred: " + throwable.getMessage());
return null;
});
}
}
解釋:
- 在上面的示例中赔嚎,我們使用
thenApply
將user
的結(jié)果作為getOrders
函數(shù)的輸入膘盖,從而獲得訂單列表
。 - 接著尤误,我們使用
thenApply
將訂單列表
作為joinUserAndOrders
函數(shù)的輸入侠畔,從而將用戶(hù)信息和訂單列表拼接在一起。 - 最后损晤,我們使用
thenAccept
將最終結(jié)果輸出到控制臺(tái)软棺。
簡(jiǎn)化代碼
- 使用
CompletionStage
的鏈?zhǔn)秸{(diào)用,我們可以將多個(gè)異步操作連接起來(lái)尤勋,形成一個(gè)完整的流程喘落,代碼更加簡(jiǎn)潔易讀。 - 相比于手動(dòng)管理多個(gè)
Future
對(duì)象最冰,CompletionStage
的鏈?zhǔn)秸{(diào)用可以更方便地處理異步操作的組合和處理瘦棋,提高代碼的可讀性和可維護(hù)性。
4.執(zhí)行效率
細(xì)心者會(huì)發(fā)現(xiàn)暖哨,上面經(jīng)常用到CompletableFuture.supplyAsync 方法來(lái)開(kāi)始一個(gè)異步任務(wù)赌朋,也恰恰就是在supplyAsync中,會(huì)使用一個(gè)異步線程來(lái)執(zhí)行傳入的 Supplier 函數(shù)篇裁。但是沛慢,這個(gè)異步線程并非由 CompletableFuture 自己創(chuàng)建,而是來(lái)自于 Java 中的 ForkJoinPool达布。
ForkJoinPool
定義: ForkJoinPool 是 Java 提供的一個(gè)線程池团甲,專(zhuān)門(mén)設(shè)計(jì)用于執(zhí)行可分解為更小任務(wù)的并行任務(wù)。
工作原理: ForkJoinPool 使用了一種分治的思想黍聂,將一個(gè)任務(wù)分解為多個(gè)子任務(wù)躺苦,并使用多個(gè)線程并行執(zhí)行這些子任務(wù)身腻,最終將結(jié)果合并,實(shí)現(xiàn)高效的并行計(jì)算圾另。
使用場(chǎng)景: ForkJoinPool 適用于處理那些可以分解為更小任務(wù)的任務(wù)霸株,例如:
- 并行計(jì)算
- 海量數(shù)據(jù)處理
- 遞歸算法
CompletableFuture.supplyAsync 和 ForkJoinPool
CompletableFuture.supplyAsync 方法默認(rèn)使用 ForkJoinPool.commonPool() 來(lái)執(zhí)行異步任務(wù)。
ForkJoinPool.commonPool() 是一個(gè)共享的 ForkJoinPool集乔,它由所有使用 ForkJoinPool 的類(lèi)共享使用。
如果你需要更精細(xì)的控制坡椒,你也可以通過(guò) CompletableFuture.supplyAsync(supplier, executor) 方法指定一個(gè)自定義的線程池來(lái)執(zhí)行異步任務(wù)扰路。
5. 總結(jié)
-
Future
是一個(gè)基礎(chǔ)的異步操作接口,簡(jiǎn)單易用倔叼。 -
CompletionStage
提供了更加靈活的異步操作組合和處理方法汗唱,支持鏈?zhǔn)秸{(diào)用,簡(jiǎn)化代碼編寫(xiě)丈攒。 -
CompletableFuture
在CompletionStage
的基礎(chǔ)上提供了更豐富的功能哩罪,更方便的控制和操作,并且更加高效巡验。
根據(jù)實(shí)際需求選擇合適的異步操作機(jī)制际插,可以有效提高程序的效率和可維護(hù)性。