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来并行执行用户验证、库存检查和支付处理。所有任务都在自定义的线程池中执行,最后通过生成订单来完成整个流程。如果在任何一个步骤中发生异常,系统会捕获并处理。

相关推荐
yuanbenshidiaos4 分钟前
c++---------数据类型
java·jvm·c++
向宇it8 分钟前
【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
java·开发语言·unity·c#·游戏引擎
Lojarro21 分钟前
【Spring】Spring框架之-AOP
java·mysql·spring
莫名其妙小饼干24 分钟前
网上球鞋竞拍系统|Java|SSM|VUE| 前后端分离
java·开发语言·maven·mssql
梦想平凡30 分钟前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
isolusion36 分钟前
Springboot的创建方式
java·spring boot·后端
TianyaOAO40 分钟前
mysql的事务控制和数据库的备份和恢复
数据库·mysql
Ewen Seong1 小时前
mysql系列5—Innodb的缓存
数据库·mysql·缓存
zjw_rp1 小时前
Spring-AOP
java·后端·spring·spring-aop
Oneforlove_twoforjob1 小时前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言