CompletableFuture 详细用法

248 阅读2分钟

CompletableFuture 是 Java 中提供的用于异步编程的类,位于 java.util.concurrent 包中。它允许你以非阻塞的方式编写并发代码,支持链式调用,并且提供了处理任务完成后的各种回调方法。以下是 CompletableFuture 的详细用法和常见场景。

1. 创建 CompletableFuture 对象

  • 手动完成

    CompletableFuture<String> future = new CompletableFuture<>();
    // 在其他地方手动完成
    future.complete("Result");
    
  • 异步任务 使用 supplyAsync() 创建一个异步任务,该方法接收 Supplier,返回结果。

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        // 模拟耗时操作
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Hello, CompletableFuture!";
    });
    

2. 链式调用

CompletableFuture 允许将多个异步操作链接在一起,按顺序执行。

  • thenApply 在当前任务执行完成后执行一个函数,处理返回值并返回新的 CompletableFuture

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenApply(result -> result + " World");
    
  • thenAcceptthenApply 类似,但不返回值,只对结果进行处理。

    CompletableFuture.supplyAsync(() -> "Hello")
        .thenAccept(result -> System.out.println("Result: " + result));
    
  • thenRun 不关心任务的返回结果,只在任务完成后执行动作。

    CompletableFuture.supplyAsync(() -> "Hello")
        .thenRun(() -> System.out.println("Task completed!"));
    

3. 异常处理

  • exceptionally 当异步操作抛出异常时,可以使用 exceptionally 进行处理并提供默认值。

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        if (Math.random() > 0.5) {
            throw new RuntimeException("Something went wrong!");
        }
        return "Success";
    }).exceptionally(ex -> "Default Value");
    
  • handle handle 方法无论任务是否异常都会执行,并且可以访问到异常对象。

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        if (Math.random() > 0.5) {
            throw new RuntimeException("Error occurred!");
        }
        return "Success";
    }).handle((result, ex) -> {
        if (ex != null) {
            return "Error handled";
        }
        return result;
    });
    

4. 组合多个 CompletableFuture

  • thenCombine 将两个 CompletableFuture 的结果组合。

    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
    ​
    CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (f1, f2) -> f1 + " " + f2);
    
  • allOf 等待所有 CompletableFuture 完成。

    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Task 1");
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Task 2");
    
    CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2);
    allOfFuture.join();  // 阻塞直到所有任务完成
    
  • anyOf 只要任意一个 CompletableFuture 完成即可返回结果。

    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Task 1");
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Task 2");
    
    CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2);
    

5. 超时处理

可以设置任务的超时,使用 orTimeoutcompleteOnTimeout 方法。

  • orTimeout 如果超过指定时间没有完成,将抛出 TimeoutException

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Task Result";
    }).orTimeout(3, TimeUnit.SECONDS);
    
  • completeOnTimeout 如果任务超时,可以返回默认值而不抛出异常。

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Task Result";
    }).completeOnTimeout("Default Result", 3, TimeUnit.SECONDS);
    

6. 阻塞获取结果

  • get()

    join()

    get()
    

    方法抛出受检异常,而

    join()
    

    方法则不抛出受检异常。

    String result = future.get();  // 阻塞,等待结果
    String result = future.join();  // 也是阻塞,但不会抛出受检异常
    

7. 取消任务

可以使用 cancel() 方法取消一个正在运行的任务。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "Task Result";
});
​
future.cancel(true);  // 取消任务