Java CompletableFuture 的一些高级用法

发布于:2025-02-11 ⋅ 阅读:(48) ⋅ 点赞:(0)

在 Java 8 中,CompletableFuture 提供了一种非常强大的方式来处理异步编程,它使得编写非阻塞代码变得更加简单和灵活。相比传统的 FutureCompletableFuture 可以让你在异步操作完成后,执行多个后续操作(如回调、合并任务、异常处理等),大大提高了代码的可读性和可维护性。今天,我们将深入探讨一些 CompletableFuture 的高级用法,帮助你更高效地利用这个工具。

1. 组合多个异步任务

CompletableFuture 支持多种方法来组合多个异步任务,这样你可以并行执行任务并等待它们完成,然后合并结果。

示例:使用 thenCombine 合并两个异步任务的结果

import java.util.concurrent.CompletableFuture;

public class CompletableFutureCombineExample {
    public static void main(String[] args) {
        // 异步任务1:计算数字
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return 10;
        });

        // 异步任务2:计算另一个数字
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return 20;
        });

        // 使用 thenCombine 将两个任务的结果合并
        CompletableFuture<Integer> result = future1.thenCombine(future2, (a, b) -> a + b);

        // 获取并打印结果
        result.thenAccept(res -> System.out.println("Combined result: " + res));
    }
}

解释:

  • thenCombine() 方法会在两个异步任务都完成后,合并它们的结果。在这个例子中,我们将两个任务的结果相加,得到了合并后的结果 30
  • 你可以根据实际需求使用不同的合并方式(如 a * ba - b 等)。

这种方式适合用于需要依赖多个异步任务结果的场景。


2. 使用 allOfanyOf 等待多个任务完成

CompletableFuture 提供了 allOf()anyOf() 方法,允许你等待多个异步任务的完成,并执行相应的后续操作。

示例:allOf 等待所有任务完成

import java.util.concurrent.CompletableFuture;

public class CompletableFutureAllOfExample {
    public static void main(String[] args) {
        // 创建多个异步任务
        CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("Task 1 completed");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        CompletableFuture<Void> task2 = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1500);
                System.out.println("Task 2 completed");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 使用 allOf 等待所有任务完成
        CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(task1, task2);

        // 等待所有任务完成后执行
        allOfFuture.thenRun(() -> System.out.println("All tasks completed"));

        // 阻塞主线程,等待任务完成
        allOfFuture.join();
    }
}

解释:

  • allOf() 方法会等待所有给定的 CompletableFuture 实例完成。如果其中任何一个任务失败,整个组合任务也会失败。
  • 在所有任务完成后,thenRun() 可以用于执行一些后续操作,比如打印“所有任务完成”。

这种方法适合用于等待多个任务并发执行完毕的场景。


示例:anyOf 等待任意一个任务完成

import java.util.concurrent.CompletableFuture;

public class CompletableFutureAnyOfExample {
    public static void main(String[] args) {
        // 创建多个异步任务
        CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("Task 1 completed");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        CompletableFuture<Void> task2 = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(500);
                System.out.println("Task 2 completed");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 使用 anyOf 等待任意一个任务完成
        CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(task1, task2);

        // 等待第一个完成的任务执行
        anyOfFuture.thenRun(() -> System.out.println("At least one task completed"));

        // 阻塞主线程,等待任务完成
        anyOfFuture.join();
    }
}

解释:

  • anyOf() 方法会等待任意一个任务完成,并在完成时执行后续操作。
  • 在这个例子中,task2 会更快完成,因此 anyOfFuture 会在 task2 完成时触发回调。

这种方式适合用于只关心哪个任务先完成的场景,例如,多个备用任务中的一个先完成即满足条件。


3. 异常处理与 handleexceptionally

CompletableFuture 提供了非常丰富的异常处理能力。你可以使用 handle()exceptionally() 方法来捕捉异步任务中的异常。

示例:使用 exceptionally 处理异常

import java.util.concurrent.CompletableFuture;

public class CompletableFutureExceptionExample {
    public static void main(String[] args) {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            if (true) {
                throw new RuntimeException("Something went wrong!");
            }
            return 42;
        });

        // 使用 exceptionally 处理异常
        future.exceptionally(ex -> {
            System.out.println("Exception occurred: " + ex.getMessage());
            return -1;  // 返回默认值
        }).thenAccept(result -> System.out.println("Result: " + result));
    }
}

解释:

  • exceptionally() 方法用于捕捉异步任务中的异常,并返回一个默认值。在这个例子中,任务抛出异常后,我们返回了一个默认值 -1,并输出异常信息。

示例:使用 handle 处理异常并返回结果

import java.util.concurrent.CompletableFuture;

public class CompletableFutureHandleExample {
    public static void main(String[] args) {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            if (true) {
                throw new RuntimeException("Something went wrong!");
            }
            return 42;
        });

        // 使用 handle 处理异常
        future.handle((result, ex) -> {
            if (ex != null) {
                System.out.println("Handled exception: " + ex.getMessage());
                return -1;  // 返回默认值
            }
            return result;
        }).thenAccept(result -> System.out.println("Result: " + result));
    }
}

解释:

  • handle() 方法不仅能处理异常,还可以处理正常结果。如果任务完成并没有抛出异常,它会返回正常的结果;如果抛出异常,它会返回一个默认值。

通过 handle()exceptionally(),你可以灵活地应对异步任务中的异常。


4. 使用 joinget 获取结果

CompletableFuture 提供了 join()get() 方法来获取异步任务的结果,它们的主要区别是异常处理方式。

  • join() 会在出现异常时抛出 CompletionException
  • get() 会在出现异常时抛出原始的异常类型。

示例:使用 join 获取结果

import java.util.concurrent.CompletableFuture;

public class CompletableFutureJoinExample {
    public static void main(String[] args) {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 42;
        });

        // 使用 join 获取结果
        Integer result = future.join();
        System.out.println("Result: " + result);
    }
}

解释:

  • 使用 join() 获取异步任务的结果,阻塞直到任务完成并返回结果。

这种方式适用于你确定任务会完成并且希望等待结果的场景。


总结

通过 CompletableFuture,你可以轻松地实现并发任务的组合、异常处理和任务同步。它不仅支持多个任务的并行执行,还能在任务完成时自动执行后续操作,避免了回调地狱的出现。了解并熟练掌握 CompletableFuture 的高级用法,将让你在处理复杂的异步任务时得心应手,提升代码的可读性和性能。

希望这篇文章帮助你更好地理解 CompletableFuture 的高级用法,提升你的编

程技巧!