CompletableFuture详细讲解

目录

一、基本概念

[1.1 异步编程](#1.1 异步编程)

[1.2 CompletableFuture简介](#1.2 CompletableFuture简介)

二、创建和完成CompletableFuture

[2.1 创建CompletableFuture对象](#2.1 创建CompletableFuture对象)

[2.2 手动完成CompletableFuture](#2.2 手动完成CompletableFuture)

[2.3 异常完成CompletableFuture](#2.3 异常完成CompletableFuture)

三、异步计算和回调

[3.1 异步任务的执行](#3.1 异步任务的执行)

[3.2 处理计算结果](#3.2 处理计算结果)

四、组合多个CompletableFuture

[4.1 thenCombine](#4.1 thenCombine)

[4.2 thenCompose](#4.2 thenCompose)

[4.3 allOf和anyOf](#4.3 allOf和anyOf)

五、异常处理

[5.1 handle](#5.1 handle)

[5.2 exceptionally](#5.2 exceptionally)

六、高级特性

[6.1 自定义执行器](#6.1 自定义执行器)

[6.2 超时控制](#6.2 超时控制)

七、实战案例

[7.1 需求描述](#7.1 需求描述)

[7.2 代码实现](#7.2 代码实现)


Java的CompletableFuture是Java 8中引入的一个功能强大的类,用于处理异步编程。它不仅提供了一种方式来表示异步计算,还提供了丰富的API来进行复杂的异步编排和处理。本文将详细讲解CompletableFuture的基本概念、使用方法以及一些高级特性,并结合实例代码进行说明。

一、基本概念

1.1 异步编程

异步编程是一种并发编程的形式,通过非阻塞方式执行任务。传统的同步编程中,任务必须按顺序执行,每个任务必须等待前一个任务完成。然而,在异步编程中,任务可以在后台执行,主线程无需等待任务完成,因而可以继续处理其他任务。这种方式在提高程序响应速度和资源利用率方面有很大优势。

1.2 CompletableFuture简介

CompletableFuture是Java提供的一个实现Future接口的类,它不仅支持传统的Future接口方法,还引入了许多新的方法来支持回调、组合、处理异常等功能。通过这些方法,开发者可以更方便地编写异步代码。

二、创建和完成CompletableFuture

2.1 创建CompletableFuture对象

创建一个CompletableFuture对象非常简单,可以通过以下几种方式:

  1. 使用CompletableFuture的静态工厂方法:

    复制代码
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!");
  2. 使用默认构造函数创建一个空的CompletableFuture,然后在未来的某个时间点手动完成它:

    复制代码
    CompletableFuture<String> future = new CompletableFuture<>();
    // 在其他线程或任务中完成这个future
    future.complete("Hello, World!");
2.2 手动完成CompletableFuture

你可以通过complete方法手动完成一个CompletableFuture

复制代码
CompletableFuture<String> future = new CompletableFuture<>();
future.complete("Hello, World!");

如果已经完成的CompletableFuture再次调用complete,将不会改变其状态。

2.3 异常完成CompletableFuture

CompletableFuture也可以以异常方式完成:

复制代码
CompletableFuture<String> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException("Something went wrong"));

三、异步计算和回调

3.1 异步任务的执行

CompletableFuture提供了多种方法来启动异步任务,例如:

  • runAsync:执行不返回结果的异步任务。

  • supplyAsync:执行并返回结果的异步任务。

java 复制代码
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    // 异步执行的任务
    System.out.println("Hello from a different thread!");
});
​
CompletableFuture<String> futureWithResult = CompletableFuture.supplyAsync(() -> {
    // 异步执行的任务,返回结果
    return "Result of the async computation";
});
3.2 处理计算结果

CompletableFuture提供了多种方法来处理异步任务的结果,例如:

  • thenApply:当CompletableFuture完成时,对其结果进行处理,并返回一个新的CompletableFuture

  • thenAccept:当CompletableFuture完成时,消费其结果,但不返回新的CompletableFuture

  • thenRun:当CompletableFuture完成时,运行一个任务,不关心其结果。

java 复制代码
CompletableFuture.supplyAsync(() -> "Hello")
    .thenApply(result -> result + ", World!")
    .thenAccept(System.out::println);

上述代码中,supplyAsync方法执行异步任务并返回结果"Hello"。thenApply方法对结果进行处理,得到"Hello, World!"。thenAccept方法消费处理后的结果,并打印输出。

四、组合多个CompletableFuture

CompletableFuture提供了多种方式来组合多个异步任务:

4.1 thenCombine

thenCombine用于将两个CompletableFuture的结果进行组合,并返回一个新的CompletableFuture

java 复制代码
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
​
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + " " + result2);
combinedFuture.thenAccept(System.out::println); // 输出 "Hello World"
4.2 thenCompose

thenCompose用于将一个CompletableFuture的结果作为另一个CompletableFuture的输入,类似于flatMap

java 复制代码
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
    .thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " World"));
​
future.thenAccept(System.out::println); // 输出 "Hello World"
4.3 allOfanyOf
  • allOf:等待所有提供的CompletableFuture都完成。

  • anyOf:只要任意一个CompletableFuture完成即可。

java 复制代码
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Result from future1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result from future2");
​
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2);
allOfFuture.thenRun(() -> System.out.println("All futures completed"));
​
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2);
anyOfFuture.thenAccept(result -> System.out.println("First completed future result: " + result));

五、异常处理

在处理异步任务时,异常处理是不可避免的。CompletableFuture提供了多种方式来处理异常:

5.1 handle

handle方法用于处理正常结果和异常情况:

java 复制代码
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (Math.random() > 0.5) {
        throw new RuntimeException("Something went wrong");
    }
    return "Success";
});
​
future.handle((result, ex) -> {
    if (ex != null) {
        return "Exception: " + ex.getMessage();
    }
    return result;
}).thenAccept(System.out::println);
5.2 exceptionally

exceptionally方法仅处理异常情况:

java 复制代码
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (Math.random() > 0.5) {
        throw new RuntimeException("Something went wrong");
    }
    return "Success";
});
​
future.exceptionally(ex -> "Exception: " + ex.getMessage())
    .thenAccept(System.out::println);

六、高级特性

6.1 自定义执行器

默认情况下,CompletableFuture使用ForkJoinPool.commonPool()作为其默认的线程池。你可以自定义执行器来控制任务的执行方式:

java 复制代码
Executor executor = Executors.newFixedThreadPool(10);
​
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello", executor)
    .thenApplyAsync(result -> result + " World", executor);
​
future.thenAcceptAsync(System.out::println, executor);
6.2 超时控制

在某些场景下,处理超时是必要的。Java 9引入了orTimeoutcompleteOnTimeout方法:

java 复制代码
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        throw new IllegalStateException(e);
    }
    return "Result";
});
​
future.orTimeout(1, TimeUnit.SECONDS)
    .exceptionally(ex -> "Timeout occurred: " + ex.getMessage())
    .thenAccept(System.out::println);

七、实战案例

为了更好地理解CompletableFuture,我们来看一个实际的例子:模拟一个复杂的业务场景,包含多个异步任务的组合和处理。

7.1 需求描述

假设我们在开发一个在线购物平台,用户下单时需要进行以下操作:

  1. 验证用户信息。

  2. 检查库存。

  3. 处理支付。

  4. 生成订单。

我们希望这些操作尽可能并行执行,以提高系统的响应速度。

7.2 代码实现
java 复制代码
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
​
public class OnlineShopping {
​
    private static final ExecutorService executor = Executors.newFixedThreadPool(10);
​
    public static void main(String[] args) {
        CompletableFuture<Void> orderFuture = CompletableFuture.supplyAsync(() -> verifyUser("user123"), executor)
            .thenCombineAsync(CompletableFuture.supplyAsync(() -> checkInventory("item456"), executor), (userVerified, inventoryChecked) -> {
                if (userVerified && inventoryChecked) {
                    return processPayment("user123", "
​
item456");
                } else {
                    throw new RuntimeException("User verification or inventory check failed");
                }
            }, executor)
            .thenApplyAsync(paymentProcessed -> generateOrder("user123", "item456"), executor)
            .thenAcceptAsync(order -> System.out.println("Order completed: " + order), executor)
            .exceptionally(ex -> {
                System.err.println("Order processing failed: " + ex.getMessage());
                return null;
            });
​
        orderFuture.join(); // 等待所有操作完成
    }
​
    private static boolean verifyUser(String userId) {
        // 模拟用户验证
        System.out.println("Verifying user: " + userId);
        return true;
    }
​
    private static boolean checkInventory(String itemId) {
        // 模拟库存检查
        System.out.println("Checking inventory for item: " + itemId);
        return true;
    }
​
    private static boolean processPayment(String userId, String itemId) {
        // 模拟支付处理
        System.out.println("Processing payment for user: " + userId + " and item: " + itemId);
        return true;
    }
​
    private static String generateOrder(String userId, String itemId) {
        // 模拟订单生成
        System.out.println("Generating order for user: " + userId + " and item: " + itemId);
        return "Order123";
    }
}

在这个示例中,我们使用了多个CompletableFuture来并行执行用户验证、库存检查和支付处理。所有任务都在自定义的线程池中执行,最后通过生成订单来完成整个流程。如果在任何一个步骤中发生异常,系统会捕获并处理。

相关推荐
qq_4330994014 分钟前
Ubuntu20.04从零安装IsaacSim/IsaacLab
数据库
Dlwyz15 分钟前
redis-击穿、穿透、雪崩
数据库·redis·缓存
Theodore_10221 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
工业甲酰苯胺2 小时前
Redis性能优化的18招
数据库·redis·性能优化
冰帝海岸2 小时前
01-spring security认证笔记
java·笔记·spring
世间万物皆对象3 小时前
Spring Boot核心概念:日志管理
java·spring boot·单元测试
没书读了3 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
小二·3 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
懒洋洋大魔王4 小时前
RocketMQ的使⽤
java·rocketmq·java-rocketmq