给CompletableFuture赋结果值
complete
# 手动设置CompletableFuture结果,调用此方法后所有等待结果的代码将能够获取到这个结果值。如 get()、join() 、thenApply()
public Future<Double> getPriceAsync(String product) {
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
new Thread(() -> {
double price = calculatePrice(product); // 无异常场景
futurePrice.complete(price); // 如果价格计算正常结束,完成Future操作并设置商品价格
}, "查询价格线程").start();
return futurePrice;
}
completedFuture
# 返回的 CompletableFuture 在创建时就处于完成状态,且持有指定的 value。
# completedFuture 方法本身是一个同步操作,不涉及线程调度或异步执行。
CompletableFuture<String> completedFuture = CompletableFuture.completedFuture("Hello, World!");
[Q&A] complete
和 completedFuture
区别
# completedFuture 创建一个新的 CompletableFuture 实例
# complete 作用于一个已经存在的CompletableFuture 实例
completeExceptionally
# 设置当前CompletableFuture对象的异常情况。所有等待结果的代码将不再获取到预期的结果值,而是会抛出或处理异常。
public Future<Double> getPriceAsync(String product) {
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
new Thread(() -> {
try {
double price = calculatePrice(product);
futurePrice.complete(price); // 如果价格计算正常结束,完成Future操作并设置商品价格
} catch (Exception ex) { // 假设 calculatePrice 抛出的是 Exception 或其子类
futurePrice.completeExceptionally(ex); // 如果价格计算出现异常,设置Future的异常状态
}
}, "查询价格线程").start();
return futurePrice;
}
提交任务
supplyAsync
# 用于创建一个异步计算任务,并返回一个CompletableFuture对象来表示该任务的结果。
# 该方法常用于在后台线程中执行计算密集型或IO密集型任务,同时允许主线程继续执行其他任务
# 默认线程池
public List<String> findPricesCompletableFuture(String product) {
List<CompletableFuture<String>> priceFutures = shops.stream().map(shop -> CompletableFuture.supplyAsync(() -> getPriceStr(product, shop))).collect(Collectors.toList());
List<String> prices = priceFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
return prices;
}
# 自定义线程池
private final Executor executorSize = Executors.newFixedThreadPool(shops.size(), ExecuterThreadFactoryBuilder.build());
public List<String> findPricesCompletableFutureCustomSize(String product) {
List<CompletableFuture<String>> priceFutures = shops.stream().map(shop -> CompletableFuture.supplyAsync(() -> getPriceStr(product, shop), executorSize)).collect(Collectors.toList());
List<String> prices = priceFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
return prices;
}
runAsync
# 当异步任务不需要返回值时,选择使用 runAsync;
# 当异步任务需要返回一个值时,选择使用 supplyAsync
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + " runAsync");
});
ForkJoinPool.commonPool-worker-1 runAsync
[Q&A] runAsync
和 supplyAsync
区别
# 当异步任务不需要返回值时,选择使用 runAsync;
# 当异步任务需要返回一个值时,选择使用 supplyAsync
处理异常
exceptionally
# 用于为CompletableFuture添加一个回调函数,当异步计算任务发生异常时,该回调函数将被调用,以便处理异常情况并提供一个备用结果。
# 如果原CompletableFuture的异步任务顺利完成,新返回的CompletableFuture将保持原状态;
# 如果原CompletableFuture的异步任务抛出异常,新返回的CompletableFuture将使用回调函数提供的备用结果。
# 1.1、传递备用结果
CompletableFuture<String> futurePrice =
CompletableFuture.supplyAsync(() -> getPriceStr(product, shop))
.exceptionally(ex -> {
// 处理异常,例如记录日志
log.error("Error while calculating price:", ex);
// 返回一个默认或替代价格字符串
return "Unknown Price";
})
.thenApply(priceStr -> {
// 这里会接收到 "Unknown Price",而不是异常
return processPriceString(priceStr);
});
String processedPrice = futurePrice.get();
# 1.2、抛出异常
# 当CompletableFuture的计算过程抛出异常时,这个异常会被CompletableFuture内部捕获,并标记该 CompletableFuture为异常完成状态。
# 当后续方法进一步处理CompletableFuture的结果时,如发现该CompletableFuture是异常完成状态,那么这些方法会抛出异常,而不执行。
# 1.2.1、CompletionException
public Future<Double> getPriceAsync4(String product) {
CompletableFuture<Double> futurePrice = CompletableFuture
.supplyAsync(() -> calculatePriceErr(product))
.exceptionally(e -> {
CompletionException ex = new CompletionException(e);
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + "自定义项目调用异常: " + e.getMessage());
throw ex;
});
return futurePrice;
}
# 1.2.2、支持特定异常类型
CompletableFuture<String> futurePrice =
CompletableFuture.supplyAsync(() -> getPriceStr(product, shop))
.exceptionally(ex -> {
log.error("Error while calculating price:", ex);
// 如果调用方需要捕获特定异常类型,可以在调用此方法的外部进行异常类型检查
throw new RuntimeException(e);
})
.thenApply(priceStr -> {
return processPriceString(priceStr);
});
try {
String processedPrice = futurePrice.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
handleNewException(cause);
}
# 2、还可以使用 whenComplete 或 handle 方法。
# 2.1、使用 whenComplete 示例:
CompletableFuture<String> futurePrice =
CompletableFuture.supplyAsync(() -> getPriceStr(product, shop))
.whenComplete((priceStr, throwable) -> {
if (throwable != null) {
log.error("Error while calculating price:", throwable);
throw new CompletionException(throwable);
} else {
validatePriceString(priceStr);
}
})
.thenApply(priceStr -> {
return processPriceString(priceStr);
});
try {
String processedPrice = futurePrice.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
handleOriginalException(cause);
}
# 2.2、使用 handle 示例:
CompletableFuture<String> futurePrice =
CompletableFuture.supplyAsync(() -> getPriceStr(product, shop))
.handle((priceStr, throwable) -> {
if (throwable != null) {
log.error("Error while calculating price:", throwable);
// 返回一个 Optional.empty() 或 null,表示保留原始异常
return null;
} else {
validatePriceString(priceStr);
return priceStr;
}
})
.thenApply(priceStr -> {
return processPriceString(priceStr);
});
try {
String processedPrice = futurePrice.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
handleOriginalException(cause);
}
注册回调
注册回调通常指的是在某个异步操作完成后,为其指定一个后续动作(即回调函数)来处理结果或异常。
回调的含义:通常意义上的回调是指在某个事件发生(如网络请求完成、定时器触发、异步操作结束等)时,系统自动调用预先注册的函数(即回调函数)。回调函数负责处理事件的结果或异常。
whenComplete [注册回调]
# whenComplete是一个注册回调的方法,用于在CompletableFuture完成(无论成功还是失败)时执行一个动作。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (someCondition) {
return "Success";
} else {
throw new RuntimeException("Task failed");
}
});
// 注册一个回调,在任务完成时执行
future.whenComplete((result, exception) -> {
if (exception == null) {
System.out.println("Task completed successfully with result: " + result);
} else {
System.err.println("Task failed with exception: " + exception.getMessage());
}
});
handle [注册回调]
#与whenComplete类似,都可以在CompletableFuture完成(无论成功还是失败)时执行一个动作。
[Q&A] whenComplete
和 handle
区别
# whenComplete不改变CompletableFuture的结果。
# handle允许你在回调中基于CompletableFuture的结果或异常生成一个新的CompletableFuture,从而可以进一步链式操作。
# 白话说就是whenComplete不会有返回值,可做一些验证类业务。handle有返回值,可以进行一些数据加工业务。
# whenComplete 示例:
CompletableFuture<String> futurePrice =
CompletableFuture.supplyAsync(() -> getPriceStr(product, shop))
.whenComplete((priceStr, throwable) -> {
if (throwable != null) {
log.error("Error while calculating price:", throwable);
throw new CompletionException(throwable);
} else {
validatePriceString(priceStr);
}
})
.thenApply(priceStr -> {
return processPriceString(priceStr);
});
try {
String processedPrice = futurePrice.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
handleOriginalException(cause);
}
# 使用 handle 示例:
CompletableFuture<String> futurePrice =
CompletableFuture.supplyAsync(() -> getPriceStr(product, shop))
.handle((priceStr, throwable) -> {
if (throwable != null) {
log.error("Error while calculating price:", throwable);
// 返回一个 Optional.empty() 或 null,表示保留原始异常
return null;
} else {
validatePriceString(priceStr);
return priceStr;
}
})
.thenApply(priceStr -> {
return processPriceString(priceStr);
});
try {
String processedPrice = futurePrice.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
handleOriginalException(cause);
}
构建计算链
thenApply
# thenApply需要等待supplyAsync执行完毕,对计算结果进行进一步加工、转换或处理。
List<CompletableFuture<String>> priceFutures =
discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product), executor))
.map(future -> future.thenApply(Quote::parse))// 一般情况下解析操作不涉及任何远程服务,也不会进行任何I/O操作,它几乎可以在第一时间进行,所以能够采用同步操作,不会带来太多的延迟。
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)))
.collect(Collectors.<CompletableFuture<String>>toList());
thenCompose
# 将前一个操作的结果作为输入传递给下一个操作,形成复杂的异步计算流水线。
# 默认线程池
List<CompletableFuture<String>> priceFutures =
discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote))))
.collect(Collectors.<CompletableFuture<String>>toList());
# 1、在主线程中,对discountShops列表进行流式处理(stream())
# 2、discountShop.getPrice(product)将在ForkJoinPool.commonPool()的某个工作线程上运行
# 3、thenApply中的Quote::parse 函数将在ForkJoinPool.commonPool()的一个工作线程上执行
# 4、() -> Discount.applyDiscount(quote)在ForkJoinPool.commonPool()的一个工作线程上执行
# 5、collect(Collectors.toList()) 在主线程中将所有 CompletableFuture<String> 收集到一个列表中
2024-04-20 09:58:57 ForkJoinPool.commonPool-worker-1 执行calculatePrice
2024-04-20 09:58:57 ForkJoinPool.commonPool-worker-3 执行calculatePrice
2024-04-20 09:58:57 ForkJoinPool.commonPool-worker-2 执行calculatePrice
2024-04-20 09:58:57 ForkJoinPool.commonPool-worker-3 parse
2024-04-20 09:58:57 ForkJoinPool.commonPool-worker-1 parse
2024-04-20 09:58:57 ForkJoinPool.commonPool-worker-2 parse
2024-04-20 09:58:57 ForkJoinPool.commonPool-worker-2 applyDiscount
2024-04-20 09:58:57 ForkJoinPool.commonPool-worker-1 applyDiscount
2024-04-20 09:58:57 ForkJoinPool.commonPool-worker-3 applyDiscount
# 自定义线程池
List<CompletableFuture<String>> priceFutures =
discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product), executor))
.map(future -> future.thenApply(Quote::parse))// 一般情况下解析操作不涉及任何远程服务,也不会进行任何I/O操作,它几乎可以在第一时间进行,所以能够采用同步操作,不会带来太多的延迟。
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)))
.collect(Collectors.<CompletableFuture<String>>toList());
# 1、stream()和map操作本身通常在调用它们的当前线程上同步执行。负责构建异步任务,但不直接执行这些任务。
# 2、discountShop.getPrice(product)将由指定的executor线程池来执行。这意味着每个折扣店的商品价格查询可能在executor线程池的不同线程上并发执行。
# 3、future->future.thenApply(Quote::parse)在executor线程池中执行。虽然该代码行中没有直接指定executor,但由于它基于已指定了executor的CompletableFuture实例进行链式调用,因此它继承了前序异步操作所使用的执行器设置,即在executor线程池中执行价格解析操作。
# 4、Discount.applyDiscount(quote)任务由executor线程池执行。因此,折扣计算可能在executor线程池的另一个线程上执行。
2024-04-20 10:00:04 thread-2 执行calculatePrice
2024-04-20 10:00:04 thread-0 执行calculatePrice
2024-04-20 10:00:04 thread-1 执行calculatePrice
2024-04-20 10:00:04 thread-0 parse
2024-04-20 10:00:04 thread-2 parse
2024-04-20 10:00:04 thread-1 parse
2024-04-20 10:00:04 thread-0 applyDiscount
2024-04-20 10:00:04 thread-1 applyDiscount
2024-04-20 10:00:04 thread-2 applyDiscount
# 默认线程池 和 自定义线程池 组合
List<CompletableFuture<String>> priceFutures =
discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)))
.collect(Collectors.<CompletableFuture<String>>toList());
2024-04-20 10:00:44 ForkJoinPool.commonPool-worker-1 执行calculatePrice
2024-04-20 10:00:44 ForkJoinPool.commonPool-worker-2 执行calculatePrice
2024-04-20 10:00:44 ForkJoinPool.commonPool-worker-3 执行calculatePrice
2024-04-20 10:00:44 ForkJoinPool.commonPool-worker-1 parse
2024-04-20 10:00:44 ForkJoinPool.commonPool-worker-2 parse
2024-04-20 10:00:44 ForkJoinPool.commonPool-worker-3 parse
2024-04-20 10:00:44 thread-0 applyDiscount
2024-04-20 10:00:44 thread-2 applyDiscount
2024-04-20 10:00:44 thread-1 applyDiscount
List<CompletableFuture<String>> priceFutures =
discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product), executor))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote))))
.collect(Collectors.<CompletableFuture<String>>toList());
2024-04-20 10:01:11 thread-0 执行calculatePrice
2024-04-20 10:01:11 thread-2 执行calculatePrice
2024-04-20 10:01:11 thread-1 执行calculatePrice
2024-04-20 10:01:11 thread-2 parse
2024-04-20 10:01:11 thread-0 parse
2024-04-20 10:01:11 thread-1 parse
2024-04-20 10:01:11 ForkJoinPool.commonPool-worker-2 applyDiscount
2024-04-20 10:01:11 ForkJoinPool.commonPool-worker-1 applyDiscount
2024-04-20 10:01:11 ForkJoinPool.commonPool-worker-3 applyDiscount
# thenApply和thenCompose都不需要等待前面全部执行完毕才开始执行。
# CompletableFuture.supplyAsync(() -> discountShop.getPrice(product), executor)一旦其完成,future.thenApply(Quote::parse) 会立即执行,
# future.thenApply(Quote::parse)一旦完成,future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor))会立即执行
2024-04-20 09:58:05 ForkJoinPool.commonPool-worker-1 执行calculatePrice
2024-04-20 09:58:05 ForkJoinPool.commonPool-worker-1 parse
2024-04-20 09:58:05 ForkJoinPool.commonPool-worker-1 applyDiscount
2024-04-20 09:58:05 ForkJoinPool.commonPool-worker-3 执行calculatePrice
2024-04-20 09:58:05 ForkJoinPool.commonPool-worker-3 parse
2024-04-20 09:58:05 ForkJoinPool.commonPool-worker-3 applyDiscount
2024-04-20 09:58:06 ForkJoinPool.commonPool-worker-2 执行calculatePrice
2024-04-20 09:58:06 ForkJoinPool.commonPool-worker-2 parse
2024-04-20 09:58:06 ForkJoinPool.commonPool-worker-2 applyDiscount
[Q&A] thenApply
和 thenCompose
区别
# thenApply方法调用是同步的:在main方法中,当执行到 jsonFuture.thenApply(json -> {...}) 这一行时,会立即创建并返回一个新的CompletableFuture<User>对象。这段代码的执行是同步的,不会阻塞主线程,立即完成并返回结果。
# thenApply指定的转换逻辑是异步执行的:转换逻辑(json -> {...})并不会立即执行,而是由CompletableFuture框架负责安排在某个线程上执行。
# thenCompose方法调用是同步的:当您在代码中调用thenCompose方法时,这个方法调用会立即执行,并返回一个新的 CompletableFuture对象。
# thenCompose指定的转换逻辑是异步执行的:与thenApply类似
# 总的来说,thenCompose方法更适合处理多个异步操作的组合,而thenApply方法则更适合处理单个异步操作的后续简单转换操作。
[Q&A] thenCompose
和 thenComposeAsync
区别
# thenCompose 和 thenComposeAsync 默认都在 ForkJoinPool.commonPool() 中异步执行。但 thenComposeAsync 提供了一个重载版本。需要指定自定义 Executor,选择使用 thenComposeAsync(…, executor)。
# 如果不需要指定自定义 Executor,两者都可以使用,效果相同。
# 其实thenCompose 也可以指定executor
public List<String> findPricesFuture(String product) {
List<CompletableFuture<String>> priceFutures =
discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenComposeAsync(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor), executor))
.collect(Collectors.<CompletableFuture<String>>toList());
2024-04-20 10:26:05 ForkJoinPool.commonPool-worker-1 执行calculatePrice
2024-04-20 10:26:05 ForkJoinPool.commonPool-worker-3 执行calculatePrice
2024-04-20 10:26:05 ForkJoinPool.commonPool-worker-2 执行calculatePrice
2024-04-20 10:26:05 ForkJoinPool.commonPool-worker-1 parse
2024-04-20 10:26:05 ForkJoinPool.commonPool-worker-2 parse
2024-04-20 10:26:05 ForkJoinPool.commonPool-worker-3 parse
2024-04-20 10:26:05 thread-1 applyDiscount
2024-04-20 10:26:05 thread-0 applyDiscount
2024-04-20 10:26:05 thread-2 applyDiscount
public List<String> findPricesFuture(String product) {
List<CompletableFuture<String>> priceFutures =
discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenComposeAsync(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)))
.collect(Collectors.<CompletableFuture<String>>toList());
2024-04-20 10:26:57 ForkJoinPool.commonPool-worker-2 执行calculatePrice
2024-04-20 10:26:57 ForkJoinPool.commonPool-worker-1 执行calculatePrice
2024-04-20 10:26:57 ForkJoinPool.commonPool-worker-3 执行calculatePrice
2024-04-20 10:26:57 ForkJoinPool.commonPool-worker-1 parse
2024-04-20 10:26:57 ForkJoinPool.commonPool-worker-3 parse
2024-04-20 10:26:57 ForkJoinPool.commonPool-worker-2 parse
2024-04-20 10:26:57 thread-1 applyDiscount
2024-04-20 10:26:57 thread-2 applyDiscount
2024-04-20 10:26:57 thread-0 applyDiscount
List<CompletableFuture<String>> priceFutures =
discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)))
.collect(Collectors.<CompletableFuture<String>>toList());
2024-04-20 10:27:27 ForkJoinPool.commonPool-worker-1 执行calculatePrice
2024-04-20 10:27:27 ForkJoinPool.commonPool-worker-2 执行calculatePrice
2024-04-20 10:27:27 ForkJoinPool.commonPool-worker-3 执行calculatePrice
2024-04-20 10:27:27 ForkJoinPool.commonPool-worker-2 parse
2024-04-20 10:27:27 ForkJoinPool.commonPool-worker-3 parse
2024-04-20 10:27:27 ForkJoinPool.commonPool-worker-1 parse
2024-04-20 10:27:27 thread-2 applyDiscount
2024-04-20 10:27:27 thread-0 applyDiscount
2024-04-20 10:27:27 thread-1 applyDiscount
# 上述几次实践,直接第3个用法就够用了
# 如下两个操作才对比的出thenComposeAsync的真实用法
List<CompletableFuture<String>> priceFutures =
discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.completedFuture(Discount.applyDiscount(quote))))
.collect(Collectors.<CompletableFuture<String>>toList());
2024-04-20 11:55:45 ForkJoinPool.commonPool-worker-2 执行calculatePrice LetsSaveBig
2024-04-20 11:55:45 ForkJoinPool.commonPool-worker-3 执行calculatePrice ShopEasy
2024-04-20 11:55:45 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:55:45 ForkJoinPool.commonPool-worker-2 parse LetsSaveBig
2024-04-20 11:55:45 ForkJoinPool.commonPool-worker-3 parse ShopEasy
2024-04-20 11:55:45 ForkJoinPool.commonPool-worker-1 parse BestPrice
2024-04-20 11:55:45 ForkJoinPool.commonPool-worker-3 applyDiscount ShopEasy
2024-04-20 11:55:45 ForkJoinPool.commonPool-worker-2 applyDiscount LetsSaveBig
2024-04-20 11:55:45 ForkJoinPool.commonPool-worker-1 applyDiscount BestPrice
List<CompletableFuture<String>> priceFutures =
discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenComposeAsync(quote -> CompletableFuture.completedFuture(Discount.applyDiscount(quote)), executor))
.collect(Collectors.<CompletableFuture<String>>toList());
2024-04-20 11:56:32 ForkJoinPool.commonPool-worker-2 执行calculatePrice LetsSaveBig
2024-04-20 11:56:32 ForkJoinPool.commonPool-worker-3 执行calculatePrice ShopEasy
2024-04-20 11:56:32 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:56:32 ForkJoinPool.commonPool-worker-3 parse ShopEasy
2024-04-20 11:56:32 ForkJoinPool.commonPool-worker-2 parse LetsSaveBig
2024-04-20 11:56:32 ForkJoinPool.commonPool-worker-1 parse BestPrice
2024-04-20 11:56:32 thread-2 applyDiscount LetsSaveBig
2024-04-20 11:56:32 thread-0 applyDiscount BestPrice
2024-04-20 11:56:32 thread-1 applyDiscount ShopEasy
thenAccept [注册回调]
# 适用对异步任务结果进行一次性消费(如打印、记录、更新状态等)而不关心返回值的场景。
# 如果CompletableFuture还未完成,那么thenAccept方法会阻塞线程,等待CompletableFuture完成后再执行accept方法。
# 默认线程池
CompletableFuture<String>[] priceFutures = discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote))))
.peek(future -> future.thenAccept(s -> System.out.println(DelayUtils.getMoment() + " " +Thread.currentThread().getName() + " thenAccept")))
.toArray(CompletableFuture[]::new);
2024-04-20 11:02:59 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:02:59 ForkJoinPool.commonPool-worker-2 执行calculatePrice LetsSaveBig
2024-04-20 11:02:59 ForkJoinPool.commonPool-worker-3 执行calculatePrice ShopEasy
2024-04-20 11:02:59 main All shops finished in 20 msecs
2024-04-20 11:02:59 ForkJoinPool.commonPool-worker-1 parse BestPrice
2024-04-20 11:02:59 ForkJoinPool.commonPool-worker-2 parse LetsSaveBig
2024-04-20 11:02:59 ForkJoinPool.commonPool-worker-3 parse ShopEasy
2024-04-20 11:02:59 ForkJoinPool.commonPool-worker-1 applyDiscount LetsSaveBig
2024-04-20 11:02:59 ForkJoinPool.commonPool-worker-5 applyDiscount BestPrice
2024-04-20 11:02:59 ForkJoinPool.commonPool-worker-4 applyDiscount ShopEasy
2024-04-20 11:03:00 ForkJoinPool.commonPool-worker-1 thenAccept LetsSaveBig price is 169.47
2024-04-20 11:03:00 ForkJoinPool.commonPool-worker-5 thenAccept BestPrice price is 123.26
2024-04-20 11:03:00 ForkJoinPool.commonPool-worker-4 thenAccept ShopEasy price is 176.08
# 如果您在创建或配置CompletableFuture时指定了一个自定义的Executor,那么thenAccept中的代码将在该线程池中执行。
# 自定义线程池
CompletableFuture<String>[] priceFutures = discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product), executor))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)))
.peek(future -> future.thenAccept(s -> System.out.println(DelayUtils.getMoment() + " " +Thread.currentThread().getName() + " thenAccept " + s)))
.toArray(CompletableFuture[]::new);
2024-04-20 11:00:50 thread-0 执行calculatePrice BestPrice
2024-04-20 11:00:50 thread-2 执行calculatePrice ShopEasy
2024-04-20 11:00:50 thread-1 执行calculatePrice LetsSaveBig
2024-04-20 11:00:50 main All shops finished in 22 msecs
2024-04-20 11:00:50 thread-0 parse BestPrice
2024-04-20 11:00:50 thread-1 parse LetsSaveBig
2024-04-20 11:00:50 thread-2 parse ShopEasy
2024-04-20 11:00:50 thread-0 applyDiscount BestPrice
2024-04-20 11:00:50 thread-2 applyDiscount ShopEasy
2024-04-20 11:00:50 thread-1 applyDiscount LetsSaveBig
2024-04-20 11:00:51 thread-1 thenAccept LetsSaveBig price is 169.47
2024-04-20 11:00:51 thread-2 thenAccept ShopEasy price is 176.08
2024-04-20 11:00:51 thread-0 thenAccept BestPrice price is 123.26
# 默认线程池 和 自定义线程池 组合
CompletableFuture<String>[] priceFutures = discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product), executor))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote))))
.peek(future -> future.thenAccept(s -> System.out.println(DelayUtils.getMoment() + " " +Thread.currentThread().getName() + " thenAccept " + s)))
.toArray(CompletableFuture[]::new);
2024-04-20 11:05:17 thread-2 执行calculatePrice ShopEasy
2024-04-20 11:05:17 thread-1 执行calculatePrice LetsSaveBig
2024-04-20 11:05:17 thread-0 执行calculatePrice BestPrice
2024-04-20 11:05:17 main All shops finished in 21 msecs
2024-04-20 11:05:17 thread-2 parse ShopEasy
2024-04-20 11:05:17 thread-1 parse LetsSaveBig
2024-04-20 11:05:17 thread-0 parse BestPrice
2024-04-20 11:05:17 ForkJoinPool.commonPool-worker-3 applyDiscount LetsSaveBig
2024-04-20 11:05:17 ForkJoinPool.commonPool-worker-1 applyDiscount BestPrice
2024-04-20 11:05:17 ForkJoinPool.commonPool-worker-2 applyDiscount ShopEasy
2024-04-20 11:05:18 ForkJoinPool.commonPool-worker-2 thenAccept ShopEasy price is 176.08
2024-04-20 11:05:18 ForkJoinPool.commonPool-worker-1 thenAccept BestPrice price is 123.26
2024-04-20 11:05:18 ForkJoinPool.commonPool-worker-3 thenAccept LetsSaveBig price is 169.47
CompletableFuture<String>[] priceFutures = discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)))
.peek(future -> future.thenAccept(s -> System.out.println(DelayUtils.getMoment() + " " +Thread.currentThread().getName() + " thenAccept " + s)))
.toArray(CompletableFuture[]::new);
2024-04-20 11:06:18 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:06:18 ForkJoinPool.commonPool-worker-3 执行calculatePrice ShopEasy
2024-04-20 11:06:18 ForkJoinPool.commonPool-worker-2 执行calculatePrice LetsSaveBig
2024-04-20 11:06:18 main All shops finished in 20 msecs
2024-04-20 11:06:18 ForkJoinPool.commonPool-worker-1 parse BestPrice
2024-04-20 11:06:18 ForkJoinPool.commonPool-worker-3 parse ShopEasy
2024-04-20 11:06:18 ForkJoinPool.commonPool-worker-2 parse LetsSaveBig
2024-04-20 11:06:18 thread-0 applyDiscount BestPrice
2024-04-20 11:06:18 thread-1 applyDiscount LetsSaveBig
2024-04-20 11:06:18 thread-2 applyDiscount ShopEasy
2024-04-20 11:06:19 thread-1 thenAccept LetsSaveBig price is 169.47
2024-04-20 11:06:19 thread-2 thenAccept ShopEasy price is 176.08
2024-04-20 11:06:19 thread-0 thenAccept BestPrice price is 123.26
# thenAccept和 thenApply、thenCompose一样都不需要等待前面全部任务执行完毕才开始执行,有一个执行完毕就马上开始
CompletableFuture<String>[] priceFutures = discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote))))
.peek(future -> future.thenAccept(s -> System.out.println(DelayUtils.getMoment() + " " +Thread.currentThread().getName() + " thenAccept")))
.toArray(CompletableFuture[]::new);
2024-04-20 10:48:23 ForkJoinPool.commonPool-worker-2 执行calculatePrice
2024-04-20 10:48:23 ForkJoinPool.commonPool-worker-2 parse
2024-04-20 10:48:23 ForkJoinPool.commonPool-worker-1 执行calculatePrice
2024-04-20 10:48:23 ForkJoinPool.commonPool-worker-1 parse
2024-04-20 10:48:23 ForkJoinPool.commonPool-worker-3 执行calculatePrice
2024-04-20 10:48:23 ForkJoinPool.commonPool-worker-3 parse
2024-04-20 10:48:24 ForkJoinPool.commonPool-worker-1 applyDiscount
2024-04-20 10:48:25 ForkJoinPool.commonPool-worker-2 applyDiscount
2024-04-20 10:48:25 ForkJoinPool.commonPool-worker-1 thenAccept
2024-04-20 10:48:26 ForkJoinPool.commonPool-worker-3 applyDiscount
2024-04-20 10:48:26 ForkJoinPool.commonPool-worker-2 thenAccept
2024-04-20 10:48:27 ForkJoinPool.commonPool-worker-3 thenAccept
[Q&A] thenAccept
和 thenAcceptAsync
区别
CompletableFuture<String>[] priceFutures = discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote))))
.peek(future -> future.thenAcceptAsync(s -> System.out.println(DelayUtils.getMoment() + " " +Thread.currentThread().getName() + " thenAccept " + s), executor))
.toArray(CompletableFuture[]::new);
2024-04-20 11:11:29 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:11:29 ForkJoinPool.commonPool-worker-2 执行calculatePrice LetsSaveBig
2024-04-20 11:11:29 ForkJoinPool.commonPool-worker-3 执行calculatePrice ShopEasy
2024-04-20 11:11:29 main All shops finished in 25 msecs
2024-04-20 11:11:29 ForkJoinPool.commonPool-worker-1 parse BestPrice
2024-04-20 11:11:29 ForkJoinPool.commonPool-worker-3 parse ShopEasy
2024-04-20 11:11:29 ForkJoinPool.commonPool-worker-2 parse LetsSaveBig
2024-04-20 11:11:29 ForkJoinPool.commonPool-worker-5 applyDiscount ShopEasy
2024-04-20 11:11:29 ForkJoinPool.commonPool-worker-1 applyDiscount BestPrice
2024-04-20 11:11:29 ForkJoinPool.commonPool-worker-2 applyDiscount LetsSaveBig
2024-04-20 11:11:30 thread-1 thenAccept BestPrice price is 123.26
2024-04-20 11:11:30 thread-0 thenAccept ShopEasy price is 176.08
2024-04-20 11:11:30 thread-2 thenAccept LetsSaveBig price is 169.47
CompletableFuture<String>[] priceFutures = discountShops.stream()
.map(discountShop -> CompletableFuture.supplyAsync(() -> discountShop.getPrice(product)))
.map(future -> future.thenApply(Quote::parse))
.map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote))))
.peek(future -> future.thenAcceptAsync(s -> System.out.println(DelayUtils.getMoment() + " " +Thread.currentThread().getName() + " thenAccept " + s)))
.toArray(CompletableFuture[]::new);
2024-04-20 11:12:15 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:12:15 ForkJoinPool.commonPool-worker-3 执行calculatePrice ShopEasy
2024-04-20 11:12:15 ForkJoinPool.commonPool-worker-2 执行calculatePrice LetsSaveBig
2024-04-20 11:12:15 main All shops finished in 20 msecs
2024-04-20 11:12:15 ForkJoinPool.commonPool-worker-1 parse BestPrice
2024-04-20 11:12:15 ForkJoinPool.commonPool-worker-2 parse LetsSaveBig
2024-04-20 11:12:15 ForkJoinPool.commonPool-worker-3 parse ShopEasy
2024-04-20 11:12:15 ForkJoinPool.commonPool-worker-3 applyDiscount ShopEasy
2024-04-20 11:12:15 ForkJoinPool.commonPool-worker-2 applyDiscount LetsSaveBig
2024-04-20 11:12:15 ForkJoinPool.commonPool-worker-1 applyDiscount BestPrice
2024-04-20 11:12:16 ForkJoinPool.commonPool-worker-1 thenAccept BestPrice price is 123.26
2024-04-20 11:12:16 ForkJoinPool.commonPool-worker-3 thenAccept ShopEasy price is 176.08
2024-04-20 11:12:16 ForkJoinPool.commonPool-worker-2 thenAccept LetsSaveBig price is 169.47
thenRun [注册回调]
# 用于在当前CompletableFuture完成后,执行一个无参无返的Runnable,通常用于执行清理、通知、其他不需要访问异步结果的任务。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " supplyAsync");
return "Hello, World!";
});
future.thenRun(() -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " Async computation finished.");
});
2024-04-20 13:50:20 ForkJoinPool.commonPool-worker-1 supplyAsync
2024-04-20 13:50:20 ForkJoinPool.commonPool-worker-1 Async computation finished.
[Q&A] thenAccept
和 thenRun
区别
thenAccept()
# 在当前CompletableFuture成功完成并获取到结果后,执行提供的Consumer函数来消费结果。如打印、存储、更新状态等,但不产生新的结果。
thenRun()
# 在当前CompletableFuture成功完成后,不使用CompletableFuture的结果,只关注任务完成的事实,执行提供的Runnable函数。适合执行与结果无关的后续操作。
thenCombine
# 用于将两个已完成的CompletableFuture结合在一起,基于它们的结果执行一个组合操作,并返回一个新的 CompletableFuture
# 默认线程池
List<CompletableFuture<String>> priceFutures = shops.stream()
.map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product))
.thenCombine(CompletableFuture.supplyAsync(() -> ExchangeService.getRate(Money.EUR, Money.USD, shop)), (price, rate) -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenCombine打折 " + shop.getName());
return price * rate;
})
.thenApply(price -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenApply " + shop.getName());
return shop.getName() + " price is " + price;
}))
.collect(Collectors.toList());
# thenCombine的组合操作(price, rate) -> price * rate将在默认的ForkJoinPool.commonPool()中异步执行。
# 两个源CompletableFuture已经完成,thenCombine方法也不会立即在当前线程中执行(price, rate) -> price * rate,而是将其推迟到后台线程执行,ForkJoinPool会安排一个工作线程执行组合操作,计算最终价格。从而避免阻塞当前线程。
2024-04-20 11:32:03 ForkJoinPool.commonPool-worker-4 getRate LetsSaveBig
2024-04-20 11:32:03 ForkJoinPool.commonPool-worker-6 getRate ShopEasy
2024-04-20 11:32:03 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:32:03 ForkJoinPool.commonPool-worker-5 执行calculatePrice ShopEasy
2024-04-20 11:32:03 ForkJoinPool.commonPool-worker-3 执行calculatePrice LetsSaveBig
2024-04-20 11:32:03 ForkJoinPool.commonPool-worker-2 getRate BestPrice
2024-04-20 11:32:04 ForkJoinPool.commonPool-worker-4 thenCombine打折 LetsSaveBig
2024-04-20 11:32:04 ForkJoinPool.commonPool-worker-6 thenCombine打折 ShopEasy
2024-04-20 11:32:04 ForkJoinPool.commonPool-worker-2 thenCombine打折 BestPrice
2024-04-20 11:32:04 ForkJoinPool.commonPool-worker-2 thenApply BestPrice
2024-04-20 11:32:04 ForkJoinPool.commonPool-worker-4 thenApply LetsSaveBig
2024-04-20 11:32:04 ForkJoinPool.commonPool-worker-6 thenApply ShopEasy
# 自定义线程池
List<CompletableFuture<String>> priceFutures = shops.stream()
.map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product), executor)
.thenCombine(CompletableFuture.supplyAsync(() -> ExchangeService.getRate(Money.EUR, Money.USD, shop), executor), (price, rate) -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenCombine打折 " + shop.getName());
return price * rate;
})
.thenApply(price -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenApply " + shop.getName());
return shop.getName() + " price is " + price;
}))
.collect(Collectors.toList());
2024-04-20 11:33:32 thread-2 执行calculatePrice LetsSaveBig
2024-04-20 11:33:32 thread-1 getRate BestPrice
2024-04-20 11:33:32 thread-0 执行calculatePrice BestPrice
2024-04-20 11:33:32 thread-2 getRate LetsSaveBig
2024-04-20 11:33:32 thread-0 执行calculatePrice ShopEasy
2024-04-20 11:33:32 thread-0 getRate ShopEasy
2024-04-20 11:33:33 thread-2 thenCombine打折 LetsSaveBig
2024-04-20 11:33:33 thread-1 thenCombine打折 BestPrice
2024-04-20 11:33:33 thread-2 thenApply LetsSaveBig
2024-04-20 11:33:33 thread-0 thenCombine打折 ShopEasy
2024-04-20 11:33:33 thread-1 thenApply BestPrice
2024-04-20 11:33:33 thread-0 thenApply ShopEasy
# 默认线程池 和 自定义线程池 组合
List<CompletableFuture<String>> priceFutures = shops.stream()
.map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product), executor)
.thenCombine(CompletableFuture.supplyAsync(() -> ExchangeService.getRate(Money.EUR, Money.USD, shop)), (price, rate) -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenCombine打折 " + shop.getName());
return price * rate;
})
.thenApply(price -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenApply " + shop.getName());
return shop.getName() + " price is " + price;
}))
.collect(Collectors.toList());
2024-04-20 11:34:31 thread-2 执行calculatePrice ShopEasy
2024-04-20 11:34:31 ForkJoinPool.commonPool-worker-2 getRate LetsSaveBig
2024-04-20 11:34:31 thread-0 执行calculatePrice BestPrice
2024-04-20 11:34:31 thread-1 执行calculatePrice LetsSaveBig
2024-04-20 11:34:31 ForkJoinPool.commonPool-worker-3 getRate ShopEasy
2024-04-20 11:34:31 ForkJoinPool.commonPool-worker-1 getRate BestPrice
2024-04-20 11:34:32 ForkJoinPool.commonPool-worker-3 thenCombine打折 ShopEasy
2024-04-20 11:34:32 ForkJoinPool.commonPool-worker-1 thenCombine打折 BestPrice
2024-04-20 11:34:32 ForkJoinPool.commonPool-worker-2 thenCombine打折 LetsSaveBig
2024-04-20 11:34:32 ForkJoinPool.commonPool-worker-3 thenApply ShopEasy
2024-04-20 11:34:32 ForkJoinPool.commonPool-worker-2 thenApply LetsSaveBig
2024-04-20 11:34:32 ForkJoinPool.commonPool-worker-1 thenApply BestPrice
List<CompletableFuture<String>> priceFutures = shops.stream()
.map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product))
.thenCombine(CompletableFuture.supplyAsync(() -> ExchangeService.getRate(Money.EUR, Money.USD, shop), executor), (price, rate) -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenCombine打折 " + shop.getName());
return price * rate;
})
.thenApply(price -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenApply " + shop.getName());
return shop.getName() + " price is " + price;
}))
.collect(Collectors.toList());
2024-04-20 11:35:29 thread-1 getRate LetsSaveBig
2024-04-20 11:35:29 ForkJoinPool.commonPool-worker-3 执行calculatePrice ShopEasy
2024-04-20 11:35:29 ForkJoinPool.commonPool-worker-2 执行calculatePrice LetsSaveBig
2024-04-20 11:35:29 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:35:29 thread-2 getRate ShopEasy
2024-04-20 11:35:29 thread-0 getRate BestPrice
2024-04-20 11:35:31 thread-1 thenCombine打折 LetsSaveBig
2024-04-20 11:35:31 thread-0 thenCombine打折 BestPrice
2024-04-20 11:35:31 thread-1 thenApply LetsSaveBig
2024-04-20 11:35:31 thread-0 thenApply BestPrice
2024-04-20 11:35:31 thread-2 thenCombine打折 ShopEasy
2024-04-20 11:35:31 thread-2 thenApply ShopEasy
[Q&A] thenCombine
和 thenCombineAsync
区别
# thenCombine:
# 这是一个过时的方法,实际上是thenCombineAsync的一个特例,即不带参数的thenCombineAsync()。在Java 9及更高版本中,直接使用thenCombineAsync()替代即可。
List<CompletableFuture<String>> priceFutures = shops.stream()
.map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product))
.thenCombine(CompletableFuture.supplyAsync(() -> ExchangeService.getRate(Money.EUR, Money.USD, shop)), (price, rate) -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenCombine打折 " + shop.getName());
return price * rate;
})
.thenApply(price -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenApply " + shop.getName());
return shop.getName() + " price is " + price;
}))
.collect(Collectors.toList());
2024-04-20 11:44:38 ForkJoinPool.commonPool-worker-5 执行calculatePrice ShopEasy
2024-04-20 11:44:38 ForkJoinPool.commonPool-worker-4 getRate LetsSaveBig
2024-04-20 11:44:38 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:44:38 ForkJoinPool.commonPool-worker-3 执行calculatePrice LetsSaveBig
2024-04-20 11:44:38 ForkJoinPool.commonPool-worker-6 getRate ShopEasy
2024-04-20 11:44:38 ForkJoinPool.commonPool-worker-2 getRate BestPrice
2024-04-20 11:44:40 ForkJoinPool.commonPool-worker-2 thenCombine打折 BestPrice
2024-04-20 11:44:40 ForkJoinPool.commonPool-worker-6 thenCombine打折 ShopEasy
2024-04-20 11:44:40 ForkJoinPool.commonPool-worker-4 thenCombine打折 LetsSaveBig
2024-04-20 11:44:40 ForkJoinPool.commonPool-worker-2 thenApply BestPrice
2024-04-20 11:44:40 ForkJoinPool.commonPool-worker-6 thenApply ShopEasy
2024-04-20 11:44:40 ForkJoinPool.commonPool-worker-4 thenApply LetsSaveBig
# thenCombineAsync: 异步执行。默认情况下,使用 ForkJoinPool.commonPool() 执行。
List<CompletableFuture<String>> priceFutures = shops.stream()
.map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product))
.thenCombineAsync(CompletableFuture.supplyAsync(() -> ExchangeService.getRate(Money.EUR, Money.USD, shop)), (price, rate) -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenCombine打折 " + shop.getName());
return price * rate;
})
.thenApply(price -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenApply " + shop.getName());
return shop.getName() + " price is " + price;
}))
.collect(Collectors.toList());
2024-04-20 11:43:55 ForkJoinPool.commonPool-worker-6 getRate ShopEasy
2024-04-20 11:43:55 ForkJoinPool.commonPool-worker-4 getRate LetsSaveBig
2024-04-20 11:43:55 ForkJoinPool.commonPool-worker-5 执行calculatePrice ShopEasy
2024-04-20 11:43:55 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:43:55 ForkJoinPool.commonPool-worker-3 执行calculatePrice LetsSaveBig
2024-04-20 11:43:55 ForkJoinPool.commonPool-worker-2 getRate BestPrice
2024-04-20 11:43:56 ForkJoinPool.commonPool-worker-2 thenCombine打折 ShopEasy
2024-04-20 11:43:56 ForkJoinPool.commonPool-worker-5 thenCombine打折 LetsSaveBig
2024-04-20 11:43:56 ForkJoinPool.commonPool-worker-3 thenCombine打折 BestPrice
2024-04-20 11:43:56 ForkJoinPool.commonPool-worker-2 thenApply ShopEasy
2024-04-20 11:43:56 ForkJoinPool.commonPool-worker-3 thenApply BestPrice
2024-04-20 11:43:56 ForkJoinPool.commonPool-worker-5 thenApply LetsSaveBig
# thenCombineAsync(executor): 异步执行,并指定一个自定义的 Executor 执行。
List<CompletableFuture<String>> priceFutures = shops.stream()
.map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product))
.thenCombineAsync(CompletableFuture.supplyAsync(() -> ExchangeService.getRate(Money.EUR, Money.USD, shop)), (price, rate) -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenCombine打折 " + shop.getName());
return price * rate;
}, executor)
.thenApply(price -> {
System.out.println(DelayUtils.getMoment() + " " + Thread.currentThread().getName() + " thenApply " + shop.getName());
return shop.getName() + " price is " + price;
}))
.collect(Collectors.toList());
2024-04-20 11:42:53 ForkJoinPool.commonPool-worker-4 getRate LetsSaveBig
2024-04-20 11:42:53 ForkJoinPool.commonPool-worker-2 getRate BestPrice
2024-04-20 11:42:53 ForkJoinPool.commonPool-worker-1 执行calculatePrice BestPrice
2024-04-20 11:42:53 ForkJoinPool.commonPool-worker-3 执行calculatePrice LetsSaveBig
2024-04-20 11:42:53 ForkJoinPool.commonPool-worker-5 执行calculatePrice ShopEasy
2024-04-20 11:42:53 ForkJoinPool.commonPool-worker-6 getRate ShopEasy
2024-04-20 11:42:54 thread-2 thenCombine打折 LetsSaveBig
2024-04-20 11:42:54 thread-0 thenCombine打折 BestPrice
2024-04-20 11:42:54 thread-2 thenApply LetsSaveBig
2024-04-20 11:42:54 thread-0 thenApply BestPrice
2024-04-20 11:42:54 thread-1 thenCombine打折 ShopEasy
2024-04-20 11:42:54 thread-1 thenApply ShopEasy
收集结果
allof
# 当所有给定的CompletableFuture都完成时(不论成功、失败、取消),返回一个仅表示所有任务的完成状态的CompletableFuture<Void>,
# 在需要等待一组异步任务全部完成后再进行下一步操作的场景中,可以使用allOf方法。
# 如果所有传入的CompletableFuture都正常完成,那么allOf返回的CompletableFuture<Void>也将正常完成,但是不返回任何具体值。
# 如果任何一个给定的CompletableFuture抛出了异常,新CompletableFuture将以CompletionException作为其结果。
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(future1, future2);
[Q&A] 调用allOf
后如何等所有结果完成?
CompletableFuture.allOf(completableFutures).get();
CompletableFuture.allOf(completableFutures).join();
List<R> join = CompletableFuture.allOf(completableFutures)
.thenApply(e -> Arrays.stream(completableFutures).map(CompletableFuture::join).collect(Collectors.toList()))
.join();
anyOf
# 等待一组CompletableFuture中的任意一个完成(无论是正常完成还是因异常而完成),并返回一个新的 CompletableFuture<Object>。
# 如果第一个完成的CompletableFuture正常完成,新CompletableFuture以该CompletableFuture的toString()结果作为其完成结果。
# 如果第一个完成的CompletableFuture抛出了异常,新CompletableFuture以CompletionException作为其完成结果。
# anyOf返回的CompletableFuture结果通常不具备实际意义,更多用于触发后续操作,而不是获取具体结果
CompletableFuture<Object> anyCompletedFuture = CompletableFuture.anyOf(future1, future2);
get
# 通过future的get()方法来获取返回值,get()阻塞当前线程直到异步计算完成,并返回计算结果。
Future<Double> priceFuture = getPriceAsync("product1");
try {
double price = futurePrice.get();
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
# 通过get(long timeout,TimeUnit unit)会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。
Future<Double> priceFuture = getPriceAsync("product1");
try {
Double price = priceFuture.get(5000, TimeUnit.MILLISECONDS); // 阻塞,最多等待5秒
System.out.println("Product price: " + price);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 重置中断状态
System.err.println("Thread interrupted while waiting for price.");
} catch (ExecutionException e) {
System.err.println("Error calculating price: " + e.getCause().getMessage());
} catch (TimeoutException e) {
System.err.println("Timed out waiting for price calculation after " + timeoutMs + " ms.");
}
# 如果在5秒内计算完成,将输出商品价格;
# 如果线程在等待期间被中断,会打印提示信息并恢复中断状态;
# 如果计算过程中出现异常,会打印异常信息;
# 若5秒后计算仍未完成,将打印超时信息。
join
# 用于阻塞当前线程,直到CompletableFuture完成并获取其结果。
# 这意味着调用join的线程将暂停执行,直到CompletableFuture的计算结果可用或发生异常。
[Q&A] join
和 get
区别
# 相同
# 两者都会阻塞当前线程,直到CompletableFuture完成
# 不同
# 异常处理
join()方法抛出的是uncheck异常,不会强制开发者抛出。如:CancellationException、CompletionException等
get()方法抛出的是check异常(抛出或者 try catch)。如:ExecutionException, InterruptedException、TimeoutException等
# get有超时机制
CompletableFuture中join()和get()方法的区别
cancel
# 尝试取消此CompletableFuture所代表的异步计算任务。
# 如果计算已经完成(无论成功还是失败),则无法取消,该方法返回 false。
# futurePrice.cancel(true); 计算任务尚未完成,系统将尽力中断执行任务的线程,并返回 true。
# futurePrice.cancel(false); 仅在任务尚未开始执行时取消它,并返回 true。
Future<Double> futurePrice = shop.getPriceAsync4("虾条");
if (!futurePrice.isDone()) { // 判断任务是否已完成
boolean cancelled = futurePrice.cancel(true); // 尝试取消任务,并允许中断线程
if (cancelled) {
System.out.println("Price calculation for '虾条' has been cancelled.");
} else {
System.out.println("Failed to cancel price calculation for '虾条'. It may have already completed.");
}
}
isCancelled
# 此方法返回true如Future对象所代表的异步任务已经被取消,否则返回false,即使任务由于某种原因(如异常)未能完成,只要没有被明确取消,该方法也会返回 false。
Future<Double> futurePrice = shop.getPriceAsync4("虾条");
if (futurePrice.isCancelled()) {
System.out.println("Price calculation for '虾条' has been cancelled.");
} else {
System.out.println("Price calculation for '虾条' is still ongoing or has completed.");
}
isDone
# 返回true如果Future对象所代表的异步任务已经完成(包括正常完成、因异常而终止或被取消),否则返回false。
Future<Double> futurePrice = shop.getPriceAsync4("虾条");
if (futurePrice.isDone()) {
System.out.println("Price calculation for '虾条' has finished.");
} else {
System.out.println("Price calculation for '虾条' is still ongoing.");
}
isCompletedNormally
# 如果CompletableFuture已经完成,并且没有因异常而终止(即任务执行成功),则返回 true。
# 如果CompletableFuture还未完成,或者已经因异常而终止(即任务执行过程中抛出了异常),则返回 false。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) {
return "Success"; // 正常完成
} else {
throw new RuntimeException("Task failed"); // 异常完成
}
});
if (future.isCompletedNormally()) {
System.out.println("Future completed normally. Result: " + future.join());
} else {
System.out.println("Future did not complete normally.");
}