CompletableFuture使用

一、类图说明

  • 实现Future和CompletionStage

二、核心方法使用

  • runAsync : 无返回值
// 无返回值+默认线程池
public static CompletableFuture<Void> runAsync(Runnable runnable) {
        return asyncRunStage(asyncPool, runnable);
}
// 无返回值+自定义线程池
public static CompletableFuture<Void> runAsync(Runnable runnable,
                                                   Executor executor) {
        return asyncRunStage(screenExecutor(executor), runnable);
}

  测试代码如下:

    /**
     * 测试无返回值+使用默认线程池
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void testCompletableFutureForRunAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
            System.out.println("test CompletableFuture run Async");
            System.out.println("execute thread name"+Thread.currentThread().getName());
        });
        System.out.println("结果->"+runAsync.get());
        System.out.println("-----------------------");
    }

    /**
     * 测试无返回值+使用自定义线程池
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void testCompletableFutureForRunAsyncForThreadPool() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
            System.out.println("test CompletableFuture run Async");
            System.out.println("execute thread name"+Thread.currentThread().getName());
        },executorService);
        System.out.println("结果->"+runAsync.get());
        executorService.shutdown();
        System.out.println("-----------------------");
    }

  测试结果如下:

  • supplyAsync:有返回值
// 有返回值+默认线程池    
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
   return asyncSupplyStage(asyncPool, supplier);
}
// 有返回值+自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor) {
   return asyncSupplyStage(screenExecutor(executor), supplier);
}

测试代码如下:

    /**
     * 测试有返回值+使用默认线程池
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void testCompletableFutureForSupplyAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {
            System.out.println("test CompletableFuture supply Async");
            System.out.println("execute thread name"+Thread.currentThread().getName());
            return "result";
        });
        System.out.println("结果->"+supplyAsync.get());
        System.out.println("-----------------------");
    }

    /**
     * 测试有返回值+使用自定义线程池
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void testCompletableFutureForSupplyAsyncForThreadPool() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {
            System.out.println("test CompletableFuture supply Async");
            System.out.println("execute thread name"+Thread.currentThread().getName());
            return "thread pool result";
        },executorService);
        System.out.println("结果->"+supplyAsync.get());
        executorService.shutdown();
        System.out.println("-----------------------");
    }

测试结果如下:

  • thenApply:表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,带有返回值。
    public CompletableFuture<Void> thenRun(Runnable action) {
        return uniRunStage(null, action);
    }

    public CompletableFuture<Void> thenRunAsync(Runnable action) {
        return uniRunStage(asyncPool, action);
    }

    public CompletableFuture<Void> thenRunAsync(Runnable action,
                                                Executor executor) {
        return uniRunStage(screenExecutor(executor), action);
    }

测试代码如下:

    /**
     * 测试thenApply
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void testCompletableFutureForThenApply() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + " cf1 do something....");
            return 1;
        });

        CompletableFuture<Void> thenRunAsync = supplyAsync1.thenRunAsync(() -> {
            System.out.println(Thread.currentThread() + " cf2 do something....");
        });

        //等待任务1执行完成
        System.out.println("cf1结果->" + supplyAsync1.get());
        //等待任务2执行完成
        System.out.println("cf2结果->" + thenRunAsync.get());
        System.out.println("-----------------------");
    }

    /**
     * 测试thenRunAsync
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void testCompletableFutureForThenApplyForThreadPool() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + " cf1 do something....");
            return 1;
        });
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        CompletableFuture<Void> thenRunAsync = supplyAsync1.thenRunAsync(() -> {
            System.out.println(Thread.currentThread() + " cf2 do something....");
        },executorService);
        System.out.println("ThenApplyForThreadPool");
        //等待任务1执行完成
        System.out.println("cf1结果->" + supplyAsync1.get());
        //等待任务2执行完成
        System.out.println("cf2结果->" + thenRunAsync.get());
        executorService.shutdown();
        System.out.println("-----------------------");
    }

    /**
     * 测试thenRunAsync
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void testCompletableFutureForThenApplyAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + " cf1 do something....");
            return 2;
        });

        CompletableFuture<Void> thenRun = supplyAsync1.thenRun(() -> {
            System.out.println(Thread.currentThread() + " cf2 do something....");
        });

        //等待任务1执行完成
        System.out.println("cf1结果->" + supplyAsync1.get());
        //等待任务2执行完成
        System.out.println("cf2结果->" + thenRun.get());
        System.out.println("-----------------------");
    }

测试结果如下:

  • allof 聚合任务(任意任务完成)
    public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
        return andTree(cfs, 0, cfs.length - 1);
    }

测试代码如下:

    /**
     * 测试allOf
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void testCompletableFutureForallOf() throws ExecutionException, InterruptedException {
        CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread() + " supplyAsync1 do something....");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("supplyAsync1 任务完成");
            return "supplyAsync1 任务完成";
        });

        CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread() + " supplyAsync2 do something....");
//                int a = 1/0;
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("supplyAsync2 任务完成");
            return "supplyAsync2 任务完成";
        });

        CompletableFuture<String> supplyAsync3 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread() + " supplyAsync3 do something....");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("supplyAsync3 任务完成");
            return "supplyAsync3 任务完成";
        });

        CompletableFuture<Void> supplyAllOf = CompletableFuture.allOf(supplyAsync1, supplyAsync2, supplyAsync3);
        System.out.println("AllOf结果->" + supplyAllOf.get());
        System.out.println("-----------------------");
    }

测试结果如下:

测试代码如下:

 // 1. 异步任务组合
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("Task 1 started");
            try { Thread.sleep(500); } catch (InterruptedException e) {}
            return 10;
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("Task 2 started");
            try { Thread.sleep(300); } catch (InterruptedException e) {}
            return 20;
        });

        // 2. 并行组合任务结果
        CompletableFuture<Integer> combined = future1.thenCombine(future2, (a, b) -> {
            System.out.println("Combining results");
            return a + b;
        });

        // 3. 异常处理
        CompletableFuture<Integer> exceptionHandling = CompletableFuture.supplyAsync(() -> {
            System.out.println("Task with exception");
            if (true) throw new RuntimeException("Simulated error");
            return 100;
        }).exceptionally(ex -> {
            System.out.println("Exception caught: " + ex.getMessage());
            return 0;
        });

        // 4. 链式回调
        CompletableFuture<Void> chain = CompletableFuture.runAsync(() -> {
            System.out.println("Initial task");
        }).thenRun(() -> {
            System.out.println("Second task");
        }).thenRun(() -> {
            System.out.println("Final task");
        });

        // 5. 等待所有任务完成
        CompletableFuture<Void> allDone = CompletableFuture.allOf(future1, future2, combined, exceptionHandling, chain);
        allDone.get(); // 等待所有任务完成

测试结果如下:

  • anyof聚合任务(任意任务完成)
    public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
        return orTree(cfs, 0, cfs.length - 1);
    }

测试代码如下:

/**
     * 测试anyOf
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void testCompletableFutureForanyOf() throws ExecutionException, InterruptedException {
        CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread() + " supplyAsync1 do something....");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("supplyAsync1 任务完成");
            return "supplyAsync1 任务完成";
        });

        CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread() + " supplyAsync2 do something....");
//                int a = 1/0;
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("supplyAsync2 任务完成");
            return "supplyAsync2 任务完成";
        });

        CompletableFuture<String> supplyAsync3 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread() + " supplyAsync3 do something....");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("supplyAsync3 任务完成");
            return "supplyAsync3 任务完成";
        });

        CompletableFuture<Object> supplyAllOf = CompletableFuture.anyOf(supplyAsync1, supplyAsync2, supplyAsync3);
        System.out.println("AllOf结果->" + supplyAllOf.get());
        System.out.println("-----------------------");
    }

测试结果如下:

  • thenCombine 合并任务

thenCombine 会把 两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理。

    public <U,V> CompletableFuture<V> thenCombine(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn) {
        return biApplyStage(null, other, fn);
    }
    private static void thenCombine() throws Exception {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                return "then";
            }
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                return "combine";
            }
        });
        CompletableFuture<String> result = future1.thenCombine(future2, new BiFunction<String, String, String>() {
            @Override
            public String apply(String t, String u) {
                return t+" "+u;
            }
        });
        System.out.println(result.get());
    }
  • acceptEither

两个CompletionStage,谁执行返回的结果快,就用那个CompletionStage的结果进行下一步的消耗操作。返回是Consumer<T>接口

    public CompletableFuture<Void> acceptEither(
        CompletionStage<? extends T> other, Consumer<? super T> action) {
        return orAcceptStage(null, other, action);
    }
    private static void acceptEither() throws Exception {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int value = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("future1="+value);
                return value;
            }
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int value = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("f2="+value);
                return value;
            }
        });
        Void unused = future1.acceptEither(future2, new Consumer<Integer>() {
            @Override
            public void accept(Integer t) {
                System.out.println(t);
            }
        }).get();
    }

测试结构如下:

  • applyToEither

两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的转化操作。返回值是

    public <U> CompletableFuture<U> applyToEither(
        CompletionStage<? extends T> other, Function<? super T, U> fn) {
        return orApplyStage(null, other, fn);
    }
private static void applyToEither() throws Exception {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int value = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("future1="+value);
                return value;
            }
        });
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int value = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("future2="+value);
                return value;
            }
        });

        CompletableFuture<Integer> result = future1.applyToEither(future2, new Function<Integer, Integer>() {
            @Override
            public Integer apply(Integer t) {
                System.out.println(t);
                return t * 2;
            }
        });
        System.out.println(result.get());
    }

测试结果如下:

  • thenAcceptBoth

当两个CompletionStage都执行完成后,把结果一块交给thenAcceptBoth来进行消耗。返回值是:BiConsumer

private static void thenAcceptBoth() throws Exception {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int value = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("future1="+value);
                return value;
            }
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int value = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("future2="+value);
                return value;
            }
        });
        future1.thenAcceptBoth(future2, new BiConsumer<Integer, Integer>() {
            @Override
            public void accept(Integer t, Integer u) {
                int result = t+u;
                System.out.println("future1="+t+";future2="+u+";");
                System.out.println("result="+result);
            }
        }).get();
    }

测试结果如下:

  • runAfterEither 

两个CompletionStage,任何一个完成了都会执行下一步的操作(Runnable)

    public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
                                                  Runnable action) {
        return orRunStage(null, other, action);
    }

测试代码如下:

private static void runAfterEither() throws Exception {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int value = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("future1="+value);
                return value;
            }
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int value = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("future2="+value);
                return value;
            }
        });
        future1.runAfterEither(future2, new Runnable() {
            @Override
            public void run() {
                System.out.println("两个任务任意一个已经完成了");
            }
        }).get();
    }

测试结果如下:

三、通用总结

区分返回值、不同的函数式接口如Runnable、Consumer、Function、BiConsumer、是否自定义线程池,根据入参和返回具体使用。

### 关于 CompletableFuture使用方法 #### 1. 基本概念 `CompletableFuture` 是 Java 中用于异步编程的一个强大工具类。相比传统的 `Future`,它不仅支持获取执行结果的功能,还扩展了许多特性,例如异常处理、手动设置结果、链式操作以及结果组合等[^1]。 --- #### 2. 示例代码展示 以下是几个典型的 `CompletableFuture` 使用场景及其对应的代码示例: ##### (1)基本异步任务与结果处理 下面的代码演示了如何创建一个异步任务,并对其结果进行进一步处理: ```java import java.util.concurrent.CompletableFuture; public class BasicExample { public static void main(String[] args) throws Exception { // 定义异步任务 CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("Executing async task..."); return 42; }); // 对结果进行转换 CompletableFuture<String> result = future.thenApply(number -> "The answer is: " + number); // 获取最终结果 String finalResult = result.get(); System.out.println(finalResult); } } ``` 此代码片段展示了如何通过 `supplyAsync()` 方法启动一个异步任务,并利用 `thenApply()` 进行后续的结果处理[^2]。 --- ##### (2)并行运行多个任务 (`allOf`) 当需要同时运行多个异步任务时,可以使用 `allOf()` 方法。该方法会在所有指定的任务完成后才继续向下执行: ```java import java.util.concurrent.CompletableFuture; import java.util.Date; public class AllOfExample { public static void main(String[] args) throws Exception { // 定义两个异步任务 CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> { try { Thread.sleep(2000); System.out.println("Task 1 completed"); } catch (InterruptedException e) { e.printStackTrace(); } }); CompletableFuture<Void> task2 = CompletableFuture.runAsync(() -> { try { Thread.sleep(3000); System.out.println("Task 2 completed"); } catch (InterruptedException e) { e.printStackTrace(); } }); // 并行运行多个任务 CompletableFuture<Void> allTasks = CompletableFuture.allOf(task1, task2); allTasks.join(); System.out.println("All tasks finished at: " + new Date()); } } ``` 在此例子中,`allOf()` 确保只有在 `task1` 和 `task2` 都完成的情况下才会打印最后的消息[^3]。 --- ##### (3)任意一个任务完成即返回 (`anyOf`) 如果只需要其中一个任务的结果而不需要等待全部完成,则可采用 `anyOf()` 方法: ```java import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class AnyOfExample { public static void main(String[] args) throws ExecutionException, InterruptedException { // 定义两个异步任务 CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); return "Result from Task 1"; } catch (InterruptedException e) { throw new RuntimeException(e); } }); CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(2000); return "Result from Task 2"; } catch (InterruptedException e) { throw new RuntimeException(e); } }); // 只要有一个任务完成就立即返回其结果 CompletableFuture<Object> anyTask = CompletableFuture.anyOf(task1, task2); System.out.println(anyTask.get()); // 主线程稍作延时以便观察效果 Thread.sleep(3000); } } ``` 这里展示了 `anyOf()` 如何快速响应最先完成的任务[^3]。 --- ##### (4)带超时机制的任务完成检测 为了防止某些长时间未完成的任务阻塞整个流程,可以通过 `get(long timeout, TimeUnit unit)` 设置超时时间: ```java import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; public class TimeoutExample { public static void main(String[] args) { CompletableFuture<Void> longRunningTask = CompletableFuture.runAsync(() -> { try { Thread.sleep(5000); // 模拟耗时任务 } catch (InterruptedException e) { e.printStackTrace(); } }); try { // 超过3秒则抛出TimeoutException longRunningTask.get(3, TimeUnit.SECONDS); System.out.println("Task completed within the time limit."); } catch (Exception e) { System.err.println("Task timed out or encountered an error: " + e.getMessage()); } } } ``` 这段代码说明了如何优雅地处理可能存在的长期挂起问题[^3]。 --- ### 总结 以上介绍了 `CompletableFuture` 的几种常见用法,包括但不限于基础异步任务管理、多任务并发控制(`allOf`)、最快完成者优先策略(`anyOf`)以及带有超时保护的操作模式。这些功能极大地增强了 Java 在异步编程领域的能力。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大道之简

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值