CompletableFuture:异步任务也能一环接一环,还能异常处理!

504 阅读3分钟

CompletableFuture 是 Java 8 引入的一个非常强大的类,它提供了一种异步编程的方式来处理并发任务。与 FutureExecutorService 不同,CompletableFuture 允许我们以声明式的方式进行异步编程,并可以实现任务的组合、错误处理、结果返回等操作。

1. 基本概念

CompletableFuture 允许你以异步的方式执行任务,并通过回调函数、链式调用等方式处理结果。它是 Future 的增强版,提供了更多的功能,如组合多个异步任务、处理异常等。

2. 使用 CompletableFuture

CompletableFuture 可以通过静态工厂方法来创建异步任务,常见的有:

  • supplyAsync: 异步执行并返回结果(适用于有返回值的任务)。
  • runAsync: 异步执行没有返回值的任务。
  • thenApply: 对结果进行转换,返回一个新的 CompletableFuture
  • thenAccept: 处理结果但不返回值。
  • exceptionally: 异常处理。
  • thenCombine: 合并两个 CompletableFuture 的结果。

3. 代码例子

下面是一个简单的 CompletableFuture 使用示例,涵盖了异步执行、结果转换、异常处理等常见操作。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureExample {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        
        // 异步执行一个任务
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("Task 1 is running in thread: " + Thread.currentThread().getName());
            return 10;
        });

        // 异步执行一个任务并处理结果
        CompletableFuture<Integer> future2 = future1.thenApplyAsync(result -> {
            System.out.println("Task 2 is running in thread: " + Thread.currentThread().getName());
            return result * 2;
        });

        // 异步执行任务3并处理
        CompletableFuture<Void> future3 = future2.thenAcceptAsync(result -> {
            System.out.println("Task 3 is running in thread: " + Thread.currentThread().getName());
            System.out.println("Result: " + result);
        });

        // 异常处理
        CompletableFuture<Integer> future4 = CompletableFuture.supplyAsync(() -> {
            if (true) {
                throw new RuntimeException("Something went wrong");
            }
            return 100;
        }).exceptionally(ex -> {
            System.out.println("Exception: " + ex.getMessage());
            return -1; // 返回一个默认值
        });

        // 等待所有任务完成
        CompletableFuture.allOf(future1, future2, future3, future4).join();
        
        // 输出最终的结果
        System.out.println("Main thread: " + Thread.currentThread().getName());
    }
}

4. 代码解析

  1. 创建异步任务

    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("Task 1 is running in thread: " + Thread.currentThread().getName());
        return 10;
    });
    

    这里我们创建了一个异步任务,它返回 10supplyAsync 用于执行一个有返回值的任务。

  2. 对结果进行处理

    CompletableFuture<Integer> future2 = future1.thenApplyAsync(result -> {
        System.out.println("Task 2 is running in thread: " + Thread.currentThread().getName());
        return result * 2;
    });
    

    thenApplyAsync 用于在第一个任务完成后继续执行的操作,返回一个新的 CompletableFuture。这里我们将 future1 的结果乘以 2。

  3. 接收并消费结果

    CompletableFuture<Void> future3 = future2.thenAcceptAsync(result -> {
        System.out.println("Task 3 is running in thread: " + Thread.currentThread().getName());
        System.out.println("Result: " + result);
    });
    

    thenAcceptAsync 用于处理结果,但不返回任何结果,只是消费 future2 的值并执行一些操作(例如输出结果)。

  4. 异常处理

    CompletableFuture<Integer> future4 = CompletableFuture.supplyAsync(() -> {
        if (true) {
            throw new RuntimeException("Something went wrong");
        }
        return 100;
    }).exceptionally(ex -> {
        System.out.println("Exception: " + ex.getMessage());
        return -1; // 返回一个默认值
    });
    

    通过 exceptionally 方法,我们可以处理任务执行中的异常,并返回一个默认值。

  5. 等待所有任务完成

    CompletableFuture.allOf(future1, future2, future3, future4).join();
    

    allOf 用于等待多个 CompletableFuture 完成,join 会阻塞直到所有任务完成。

5. 结果输出

运行此代码时,您可能会看到如下输出(根据线程的调度,输出的顺序可能不同):

Task 1 is running in thread: ForkJoinPool.commonPool-worker-1
Task 2 is running in thread: ForkJoinPool.commonPool-worker-2
Task 3 is running in thread: ForkJoinPool.commonPool-worker-3
Result: 20
Exception: Something went wrong
Main thread: main

6. 总结

  • CompletableFuture 提供了更强大的异步编程能力,可以执行异步任务并组合多个任务。
  • 支持 thenApply, thenAccept, thenCombine, exceptionally 等方法来实现结果的处理和任务的组合。
  • 通过 CompletableFuture.allOf()CompletableFuture.anyOf() 可以等待多个异步任务的完成,适合并发和异步编程场景。