CompletableFuture 常见方法总结

给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] completecompletedFuture 区别

# 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] runAsyncsupplyAsync 区别

# 当异步任务不需要返回值时,选择使用 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] whenCompletehandle 区别

# 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] thenApplythenCompose 区别

# thenApply方法调用是同步的:在main方法中,当执行到 jsonFuture.thenApply(json -> {...}) 这一行时,会立即创建并返回一个新的CompletableFuture<User>对象。这段代码的执行是同步的,不会阻塞主线程,立即完成并返回结果。
# thenApply指定的转换逻辑是异步执行的:转换逻辑(json -> {...})并不会立即执行,而是由CompletableFuture框架负责安排在某个线程上执行。

# thenCompose方法调用是同步的:当您在代码中调用thenCompose方法时,这个方法调用会立即执行,并返回一个新的 CompletableFuture对象。
# thenCompose指定的转换逻辑是异步执行的:与thenApply类似

# 总的来说,thenCompose方法更适合处理多个异步操作的组合,而thenApply方法则更适合处理单个异步操作的后续简单转换操作。

[Q&A] thenComposethenComposeAsync 区别

# 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] thenAcceptthenAcceptAsync 区别

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] thenAcceptthenRun 区别

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] thenCombinethenCombineAsync 区别

# 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] joinget 区别

# 相同
# 两者都会阻塞当前线程,直到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.");
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值