【并发编程】Java8 - CompletableFuture,增强版Future

1. 简介

  CompletableFuture是Java8的新特性,在Future基础上,增加流式计算、函数式编程、完成通知、自定义异常、多个Future组合处理等能力,使得在多线程协同处理时更加顺利。

2. 相关博客

  【并发编程】Java5 - Future,基本使用
  【并发编程】Java5 - CompletionService,将异步执行与获取结果分离
  【并发编程】Guava - ListenableFuture,避免Future获取阻塞问题,增加回调

3. CompletableFuture应用

3.1 supplyAsync/runAsync

  supplyAsync和runAsync都可以创建CompletableFuture实例,并异步执行提交的任务。区别在于:supplyAsync带有返回值,runAsync无返回值。

  • 创建带有返回值的异步任务
/**
 * 创建带有返回值的异步任务
 */
@Test
public void testSupplyAsync() throws ExecutionException, InterruptedException {
    CompletableFuture<Boolean> completableFuture = CompletableFuture.supplyAsync(() -> {
        log.info("任务执行中...");
        return Boolean.TRUE;
    });

    Boolean result = completableFuture.get();
    log.info("执行结果:" + result);
}

  控制台输出:

19:56:10.381 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务执行中...
19:56:10.393 [main] INFO com.c3stones.test.CompletableFutureTest - 执行结果:true
  • 创建带有返回值的异步任务,并指定线程池
/**
 * 创建带有返回值的异步任务,并指定线程池
 */
@Test
public void testSupplyAsync2() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newSingleThreadExecutor();

    CompletableFuture<Boolean> completableFuture = CompletableFuture.supplyAsync(() -> {
        log.info("任务执行中...");
        return Boolean.TRUE;
    }, executorService);

    Boolean result = completableFuture.get();
    log.info("执行结果:" + result);
}

  控制台输出:

19:57:32.507 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务执行中...
19:57:32.513 [main] INFO com.c3stones.test.CompletableFutureTest - 执行结果:true

  不指定线程池默认使用ForkJoinPool.commonPool()。

  • 创建无返回值的异步任务
/**
 * 创建无返回值的异步任务
 */
@Test
public void testRunAsync() throws ExecutionException, InterruptedException {
    CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
        log.info("任务执行中...");
    });

    Void result = completableFuture.get();
    log.info("执行结果:" + result);
}

  控制台输出:

19:59:29.721 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务执行中...
19:59:29.729 [main] INFO com.c3stones.test.CompletableFutureTest - 执行结果:null
  • 创建无返回值的异步任务,并指定线程池
/**
 * 创建无返回值的异步任务,并指定线程池
 */
@Test
public void testRunAsync2() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
        log.info("任务执行中...");
    }, executorService);

    Void result = completableFuture.get();
    log.info("执行结果:" + result);
}

  控制台输出:

20:00:06.732 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务执行中...
20:00:06.740 [main] INFO com.c3stones.test.CompletableFutureTest - 执行结果:null
3.2 流式连接函数
3.2.1 thenApply/thenApplyAsync

  thenApply和thenApplyAsync都是任务执行完成后的回调函数,并将任务的返回结果作为入参,并带有返回值。区别在于:thenApply执行回调函数和任务使用的是同一线程,而thenApplyAsync会使用不同的线程,并且thenApplyAsync支持指定线程池。

  • thenApply
/**
 * 任务1执行完返回结果<br/>
 * 回调函数入参为任务1的返回结果,并带有返回值
 * <p>
 * 相同线程执行
 * </p>
 */
@Test
public void testThenApply() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = completableFuture1.thenApply((result) -> {
        log.info("回调函数执行中...");
        return result * 10;
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:08:40.723 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:08:40.730 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
20:08:40.731 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:08:40.731 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:100
  • thenApplyAsync
/**
 * 任务1执行完返回结果<br/>
 * 回调函数入参为任务1的返回结果,并带有返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testThenApplyAsync() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    }, executorService);

    CompletableFuture<Integer> completableFuture2 = completableFuture1.thenApplyAsync((result) -> {
        log.info("回调函数执行中...");
        return result * 10;
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:10:30.067 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:10:30.074 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:10:30.075 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
20:10:30.075 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:100
3.2.2 thenAccept/thenAcceptAsync

  thenAccept和thenAcceptAsync都是任务执行完成后的回调函数,并将任务的返回结果作为入参,但无返回值。区别在于:thenAccept执行回调函数和任务使用的是同一线程,而thenAcceptAsync会使用不同的线程,并且thenAcceptAsync支持指定线程池。

  • thenAccept
/**
 * 任务1执行完返回结果<br/>
 * 回调函数入参为任务1的返回结果,无返回值
 * <p>
 * 相同线程执行
 * </p>
 */
@Test
public void testThenAccept() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Void> completableFuture2 = completableFuture1.thenAccept((result) -> {
        log.info("回调函数执行中...");
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:13:22.635 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:13:22.641 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:13:22.641 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
20:13:22.642 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
  • thenAcceptAsync
/**
 * 任务1执行完返回结果<br/>
 * 回调函数入参为任务1的返回结果,无返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testThenAcceptAsync() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    }, executorService);

    CompletableFuture<Void> completableFuture2 = completableFuture1.thenAcceptAsync((result) -> {
        log.info("回调函数执行中...");
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:14:24.234 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:14:24.240 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:14:24.303 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
20:14:24.304 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
3.2.3 thenRun/thenRunAsync

  thenRun和thenRunAsync都是任务执行完成后的回调函数,但无入参,也无返回值。区别在于:thenRun执行回调函数和任务使用的是同一线程,而thenRunAsync会使用不同的线程,并且thenRunAsync支持指定线程池。

  • thenRun
/**
 * 任务1执行完返回结果<br/>
 * 回调函数无入参,无返回值
 * <p>
 * 相同线程执行
 * </p>
 */
@Test
public void testThenRun() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Void> completableFuture2 = completableFuture1.thenRun(() -> {
        log.info("回调函数执行中...");
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:17:37.329 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:17:37.335 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
20:17:37.335 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:17:37.335 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
  • thenRunAsync
/**
 * 任务1执行完返回结果<br/>
 * 回调函数无入参,无返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testThenRunAsync() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    }, executorService);

    CompletableFuture<Void> completableFuture2 = completableFuture1.thenRunAsync(() -> {
        log.info("回调函数执行中...");
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:18:39.630 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:18:39.638 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:18:39.656 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
20:18:39.656 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
3.2.4 whenComplete/whenCompleteAsync

  whenComplete和whenCompleteAsync都是任务执行完成后的回调函数,带有两个参数,参数1为任务指定的返回结果,参数2为任务2执行时抛出的异常。调用get方法获取任务的执行结果时,如果任务执行正常,则正常返回结果,如果执行异常,则抛出异常。区别在于:whenComplete执行回调函数和任务使用的是同一线程,而whenCompleteAsync会使用不同的线程,并且whenCompleteAsync支持指定线程池。

  • whenComplete
/**
 * 任务1执行成功<br/>
 * 回调函数入参1为任务1的返回结果,入参2为null
 * <p>
 * 相同线程执行
 * </p>
 */
@Test
public void testWhenComplete() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = completableFuture1.whenComplete((result, exception) -> {
        if (exception != null) {
            log.error("任务 1 返回异常:" + exception.getMessage());
        } else {
            log.info("任务 1 返回结果:" + result);
        }
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:24:25.589 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:24:25.597 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:24:25.597 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:24:25.598 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:10
/**
 * 任务1执行抛出异常<br/>
 * 回调函数入参1为null.入参2为任务1抛出的异常
 * <p>
 * 相同线程执行
 * </p>
 */
@Test
public void testWhenCompleteException() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        int a = 1 / 0;
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = completableFuture1.whenComplete((result, exception) -> {
        if (exception != null) {
            log.error("任务 1 返回异常:" + exception.getMessage());
        } else {
            log.info("任务 1 返回结果:" + result);
        }
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:25:34.521 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:25:34.529 [ForkJoinPool.commonPool-worker-1] ERROR com.c3stones.test.CompletableFutureTest - 任务 1 返回异常:java.lang.ArithmeticException: / by zero

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testWhenCompleteException(CompletableFutureTest.java:263)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testWhenCompleteException$18(CompletableFutureTest.java:251)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
  • whenCompleteAsync
/**
 * 任务1执行完返回结果<br/>
 * 回调函数入参1为null.入参2为任务1抛出的异常
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testWhenCompleteAsync() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    }, executorService);

    CompletableFuture<Integer> completableFuture2 = completableFuture1.whenCompleteAsync((result, exception) -> {
        if (exception != null) {
            log.error("任务 1 返回异常:" + exception.getMessage());
        } else {
            log.info("任务 1 返回结果:" + result);
        }
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:37:29.881 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:37:29.886 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:37:29.887 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:37:29.887 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:10
/**
 * 任务1执行抛出异常<br/>
 * 回调函数入参1为null.入参2为任务1抛出的异常
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testWhenCompleteAsyncException() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        int a = 1 / 0;
        return 10;
    }, executorService);

    CompletableFuture<Integer> completableFuture2 = completableFuture1.whenCompleteAsync((result, exception) -> {
        if (exception != null) {
            log.error("任务 1 返回异常:" + exception.getMessage());
        } else {
            log.info("任务 1 返回结果:" + result);
        }
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:39:00.814 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:39:00.821 [pool-1-thread-2] ERROR com.c3stones.test.CompletableFutureTest - 任务 1 返回异常:java.lang.ArithmeticException: / by zero

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testWhenCompleteAsyncException(CompletableFutureTest.java:320)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testWhenCompleteAsyncException$22(CompletableFutureTest.java:308)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
3.2.5 handle/handleAsync

  handle和handleAsync都是任务执行完成后的回调函数,带有两个参数,参数1为任务指定的返回结果,参数2为任务2执行时抛出的异常,并且带有返回值。调用get方法获取任务的执行结果时,如果任务执行正常,则正常返回结果,如果执行异常,则抛出异常。区别在于:handle执行回调函数和任务使用的是同一线程,而handleAsync会使用不同的线程,并且handleAsync支持指定线程池。和whenComplete和whenCompleteAsync区别为:当发生异常时,whenComplete和whenCompleteAsync不会吞掉异常,即最终结果还是会抛出异常;而handle和handleAsync可以将异常进行替换,即最终结果可以是替换异常后的其他正常结果。

  • handle
/**
 * 任务1执行完返回结果<br/>
 * 回调函数入参1为任务1的返回结果,入参2为null,并带有返回值
 * <p>
 * 相同线程执行
 * </p>
 */
@Test
public void testHandle() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = completableFuture1.handle((result, exception) -> {
        if (exception != null) {
            log.error("任务 1 返回异常:" + exception.getMessage());
        } else {
            log.info("任务 1 返回结果:" + result);
        }
        return result * 10;
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:43:18.876 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:43:18.881 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:43:18.881 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:43:18.881 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:100
/**
 * 任务1执行抛出异常<br/>
 * 回调函数入参1为任务1的返回结果,入参2为null,并带有返回值
 * <p>
 * 相同线程执行
 * </p>
 */
@Test
public void testHandleException() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        int a = 1 / 0;
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = completableFuture1.handle((result, exception) -> {
        if (exception != null) {
            log.error("任务 1 返回异常:" + exception.getMessage());
        } else {
            log.info("任务 1 返回结果:" + result);
        }
        return result * 10;
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:45:24.873 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:45:24.888 [main] ERROR com.c3stones.test.CompletableFutureTest - 任务 1 返回异常:java.lang.ArithmeticException: / by zero

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testHandleException(CompletableFutureTest.java:375)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testHandleException$26(CompletableFutureTest.java:362)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
  • handleAsync
/**
 * 任务1执行完返回结果<br/>
 * 回调函数入参1为任务1的返回结果,入参2为null,并带有返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testHandleAsync() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    }, executorService);

    CompletableFuture<Integer> completableFuture2 = completableFuture1.handleAsync((result, exception) -> {
        if (exception != null) {
            log.error("任务 1 返回异常:" + exception.getMessage());
        } else {
            log.info("任务 1 返回结果:" + result);
        }
        return result * 10;
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:46:43.338 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:46:43.345 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:46:43.347 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
20:46:43.347 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:100
/**
 * 任务1执行抛出异常<br/>
 * 回调函数入参1为任务1的返回结果,入参2为null,并带有返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testHandleAsyncException() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        int a = 1 / 0;
        return 10;
    }, executorService);

    CompletableFuture<Integer> completableFuture2 = completableFuture1.handleAsync((result, exception) -> {
        if (exception != null) {
            log.error("任务 1 返回异常:" + exception.getMessage());
        } else {
            log.info("任务 1 返回结果:" + result);
        }
        return result * 10;
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("回调函数返回结果:" + completableFuture2.get());
}

  控制台输出:

20:47:22.106 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
20:47:22.113 [pool-1-thread-2] ERROR com.c3stones.test.CompletableFutureTest - 任务 1 返回异常:java.lang.ArithmeticException: / by zero

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testHandleAsyncException(CompletableFutureTest.java:434)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testHandleAsyncException$30(CompletableFutureTest.java:421)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
3.3 多任务组合
3.3.1 thenCombine/thenCombineAsync

  thenCombine和thenCombineAsync都是将两个异步任务组合后处理。当两个任务都执行完成后,执行回调函数。回调函数会将两个任务的返回结果作为入参,并带有返回值。如果两个任务有一个执行异常,则抛出异常。区别在于:thenCombine执行回调函数时会公用执行两个任务的其中一个的线程,而thenCombineAsync会使用不同的线程,并且thenCombineAsync支持指定线程池。

  • thenCombine
/**
 * 任务1和任务2都执行成功,再执行回调函数<br/>
 * 回调函数入参为任务1和任务2的返回结果,并带有返回值
 * <p>
 * 回调函数公用两个任务其中一个线程执行
 * </p>
 */
@Test
public void testThenCombine() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 2 执行中...");
        return 20;
    });

    CompletableFuture<Integer> completableFuture3 = completableFuture1.thenCombine(completableFuture2, (result1, result2) -> {
        log.info("回调函数获取到 任务 1 结果:" + result1 + ",获取到任务 2 结果:" + result2);
        log.info("回调函数执行中...");
        return result1 + result2;
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("任务 2 返回结果:" + completableFuture2.get());
    log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:15:55.676 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:15:55.676 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:15:55.684 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
21:15:55.684 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到 任务 1 结果:10,获取到任务 2 结果:20
21:15:55.684 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
21:15:55.684 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
21:15:55.684 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:30
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数入参为任务1和任务2的返回结果,并带有返回值
 * <p>
 * 回调函数公用两个任务其中一个线程执行
 * </p>
 */
@Test
public void testThenCombineException() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 2 执行中...");
        int a = 1 / 0;
        return 20;
    });

    CompletableFuture<Integer> completableFuture3 = completableFuture1.thenCombine(completableFuture2, (result1, result2) -> {
        log.info("回调函数获取到 任务 1 结果:" + result1 + ",获取到任务 2 结果:" + result2);
        log.info("回调函数执行中...");
        return result1 + result2;
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("任务 2 返回结果:" + completableFuture2.get());
    log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:17:24.832 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:17:24.832 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:17:24.839 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testThenCombineException(CompletableFutureTest.java:495)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testThenCombineException$36(CompletableFutureTest.java:484)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
  • thenCombineAsync
/**
 * 任务1和任务2都执行成功,再执行回调函数<br/>
 * 回调函数入参为任务1和任务2的返回结果,并带有返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testThenCombineAsync() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    }, executorService);

    CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 2 执行中...");
        return 20;
    }, executorService);

    CompletableFuture<Integer> completableFuture3 = completableFuture1.thenCombineAsync(completableFuture2, (result1, result2) -> {
        log.info("回调函数获取到 任务 1 结果:" + result1 + ",获取到任务 2 结果:" + result2);
        log.info("回调函数执行中...");
        return result1 + result2;
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("任务 2 返回结果:" + completableFuture2.get());
    log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:19:29.638 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:19:29.636 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:19:29.642 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
21:19:29.642 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
21:19:29.645 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到 任务 1 结果:10,获取到任务 2 结果:20
21:19:29.645 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
21:19:29.645 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:30
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数入参为任务1和任务2的返回结果,并带有返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testThenCombineAsyncException() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    }, executorService);

    CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 2 执行中...");
        int a = 1 / 0;
        return 20;
    }, executorService);

    CompletableFuture<Integer> completableFuture3 = completableFuture1.thenCombineAsync(completableFuture2, (result1, result2) -> {
        log.info("回调函数获取到 任务 1 结果:" + result1 + ",获取到任务 2 结果:" + result2);
        log.info("回调函数执行中...");
        return result1 + result2;
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("任务 2 返回结果:" + completableFuture2.get());
    log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:23:26.457 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:23:26.463 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
21:23:26.467 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testThenCombineAsyncException(CompletableFutureTest.java:560)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testThenCombineAsyncException$42(CompletableFutureTest.java:549)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
3.3.2 thenAcceptBoth/thenAcceptBothAsync

  thenAcceptBoth和thenAcceptBothAsync都是将两个异步任务组合后处理。当两个任务都执行完成后,执行回调函数。回调函数会将两个任务的返回结果作为入参,但无返回值。如果两个任务有一个执行异常,则抛出异常。区别在于:thenAcceptBoth执行回调函数时会公用执行两个任务的其中一个的线程,而thenAcceptBothAsync会使用不同的线程,并且thenAcceptBothAsync支持指定线程池。

  • thenAcceptBoth
/**
 * 任务1和任务2都执行成功,再执行回调函数<br/>
 * 回调函数入参为任务1和任务2的返回结果,无返回值
 * <p>
 * 回调函数公用两个任务其中一个线程执行
 * </p>
 */
@Test
public void testThenAcceptBoth() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 2 执行中...");
        return 20;
    });

    CompletableFuture<Void> completableFuture3 = completableFuture1.thenAcceptBoth(completableFuture2, (result1, result2) -> {
        log.info("回调函数获取到 任务 1 结果:" + result1 + ",获取到任务 2 结果:" + result2);
        log.info("回调函数执行中...");
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("任务 2 返回结果:" + completableFuture2.get());
    log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:31:14.624 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:31:14.624 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:31:14.630 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
21:31:14.630 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到 任务 1 结果:10,获取到任务 2 结果:20
21:31:14.630 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
21:31:14.630 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
21:31:14.630 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数入参为任务1和任务2的返回结果,无返回值
 * <p>
 * 回调函数公用两个任务其中一个线程执行
 * </p>
 */
@Test
public void testThenAcceptBothException() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 2 执行中...");
        int a = 1 / 0;
        return 20;
    });

    CompletableFuture<Void> completableFuture3 = completableFuture1.thenAcceptBoth(completableFuture2, (result1, result2) -> {
        log.info("回调函数获取到 任务 1 结果:" + result1 + ",获取到任务 2 结果:" + result2);
        log.info("回调函数执行中...");
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("任务 2 返回结果:" + completableFuture2.get());
    log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:33:23.532 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:33:23.527 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:33:23.539 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testThenAcceptBothException(CompletableFutureTest.java:619)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testThenAcceptBothException$48(CompletableFutureTest.java:609)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
  • thenAcceptBothAsync
/**
 * 任务1和任务2都执行成功,再执行回调函数<br/>
 * 回调函数入参为任务1和任务2的返回结果,无返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testThenAcceptBothAsync() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    }, executorService);

    CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 2 执行中...");
        return 20;
    }, executorService);

    CompletableFuture<Void> completableFuture3 = completableFuture1.thenAcceptBothAsync(completableFuture2, (result1, result2) -> {
        log.info("回调函数获取到 任务 1 结果:" + result1 + ",获取到任务 2 结果:" + result2);
        log.info("回调函数执行中...");
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("任务 2 返回结果:" + completableFuture2.get());
    log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:34:44.099 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:34:44.099 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:34:44.105 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
21:34:44.106 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
21:34:44.106 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到 任务 1 结果:10,获取到任务 2 结果:20
21:34:44.106 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
21:34:44.106 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数入参为任务1和任务2的返回结果,无返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testThenAcceptBothAsyncException() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newCachedThreadPool();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    }, executorService);

    CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 2 执行中...");
        int a = 1 / 0;
        return 20;
    }, executorService);

    CompletableFuture<Void> completableFuture3 = completableFuture1.thenAcceptBothAsync(completableFuture2, (result1, result2) -> {
        log.info("回调函数获取到 任务 1 结果:" + result1 + ",获取到任务 2 结果:" + result2);
        log.info("回调函数执行中...");
    }, executorService);

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("任务 2 返回结果:" + completableFuture2.get());
    log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:35:31.832 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:35:31.833 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:35:31.839 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testThenAcceptBothAsyncException(CompletableFutureTest.java:682)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testThenAcceptBothAsyncException$54(CompletableFutureTest.java:672)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
3.3.3 runAfterBoth/runAfterBothAsync

  runAfterBoth和runAfterBothAsync都是将两个异步任务组合后处理。当两个任务都执行完成后,执行回调函数。回调函数无入参,也无返回值。如果两个任务有一个执行异常,则抛出异常。区别在于:runAfterBoth执行回调函数时会公用执行两个任务的其中一个的线程,而runAfterBothAsync会使用不同的线程,并且runAfterBothAsync支持指定线程池。

  • runAfterBoth
/**
 * 任务1和任务2都执行成功,再执行回调函数<br/>
 * 回调函数无入参,无返回值
 * <p>
 * 回调函数公用两个任务其中一个线程执行
 * </p>
 */
@Test
public void testRunAfterBoth() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 2 执行中...");
        return 20;
    });

    CompletableFuture<Void> completableFuture3 = completableFuture1.runAfterBoth(completableFuture2, () -> {
        log.info("回调函数执行中...");
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("任务 2 返回结果:" + completableFuture2.get());
    log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:39:33.677 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:39:33.683 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
21:39:33.684 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:39:33.684 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
21:39:33.684 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
21:39:33.684 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数无入参,无返回值
 * <p>
 * 回调函数公用两个任务其中一个线程执行
 * </p>
 */
@Test
public void testRunAfterBothException() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        return 10;
    });

    CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 2 执行中...");
        int a = 1 / 0;
        return 20;
    });

    CompletableFuture<Void> completableFuture3 = completableFuture1.runAfterBoth(completableFuture2, () -> {
        log.info("回调函数执行中...");
    });

    log.info("任务 1 返回结果:" + completableFuture1.get());
    log.info("任务 2 返回结果:" + completableFuture2.get());
    log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:40:44.127 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:40:44.128 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:40:44.136 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testRunAfterBothException(CompletableFutureTest.java:739)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testRunAfterBothException$60(CompletableFutureTest.java:730)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run$$$capture(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
  • runAfterBothAsync
/**
 * 任务1和任务2都执行成功,再执行回调函数<br/>
 * 回调函数无入参,无返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testRunAfterBothAsync() throws ExecutionException, InterruptedException {
	ExecutorService executorService = Executors.newCachedThreadPool();

	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		return 10;
	}, executorService);

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		return 20;
	}, executorService);

	CompletableFuture<Void> completableFuture3 = completableFuture1.runAfterBothAsync(completableFuture2, () -> {
		log.info("回调函数执行中...");
	}, executorService);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:42:19.533 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:42:19.533 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:42:19.539 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
21:42:19.540 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
21:42:19.546 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
21:42:19.546 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数无入参,无返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testRunAfterBothAsyncException() throws ExecutionException, InterruptedException {
	ExecutorService executorService = Executors.newCachedThreadPool();

	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		return 10;
	}, executorService);

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		int a = 1 / 0;
		return 20;
	}, executorService);

	CompletableFuture<Void> completableFuture3 = completableFuture1.runAfterBothAsync(completableFuture2, () -> {
		log.info("回调函数执行中...");
	}, executorService);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

21:43:36.457 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
21:43:36.464 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
21:43:36.464 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testRunAfterBothAsyncException(CompletableFutureTest.java:800)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testRunAfterBothAsyncException$66(CompletableFutureTest.java:791)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
3.3.4 applyToEither/applyToEitherAsync

  applyToEither和applyToEitherAsync都是将两个异步任务组合后处理。回调函数会将第一个完成的任务的返回结果作为入参,并带有返回值。如果两个任务有一个执行异常,则抛出异常。区别在于:applyToEither执行回调函数时会公用第一个完成的任务的线程,而applyToEitherAsync会使用不同的线程,并且applyToEitherAsync支持指定线程池。

  • applyToEither
/**
 * 任务1或任务2执行成功,再执行回调函数<br/>
 * 回调函数入参为第一个完成的任务的返回结果,并带有返回值
 * <p>
 * 回调函数和第一个完成的任务使用相同线程执行
 * </p>
 */
@Test
public void testApplyToEither() throws ExecutionException, InterruptedException {
	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	});

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 20;
	});

	CompletableFuture<Integer> completableFuture3 = completableFuture1.applyToEither(completableFuture2, (result) -> {
		log.info("回调函数获取到结果:" + result);
		log.info("回调函数执行中...");
		return result * 10;
	});

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:08:52.369 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:08:52.371 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:08:53.376 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到结果:10
22:08:53.376 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
22:08:53.376 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:08:54.378 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
22:08:54.379 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:100
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数入参为第一个完成的任务的返回结果,并带有返回值
 * <p>
 * 回调函数和第一个完成的任务使用相同线程执行
 * </p>
 */
@Test
public void testApplyToEitherException() throws ExecutionException, InterruptedException {
	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	});

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		int a = 1 / 0;
		return 20;
	});

	CompletableFuture<Integer> completableFuture3 = completableFuture1.applyToEither(completableFuture2, (result) -> {
		log.info("回调函数获取到结果:" + result);
		log.info("回调函数执行中...");
		return result * 10;
	});

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:11:25.616 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:11:25.616 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:11:26.621 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:11:26.621 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到结果:10
22:11:26.621 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testApplyToEitherException(CompletableFutureTest.java:881)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testApplyToEitherException$72(CompletableFutureTest.java:870)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
  • applyToEitherAsync
/**
 * 任务1或任务2执行成功,再执行回调函数<br/>
 * 回调函数入参为第一个完成的任务的返回结果,并带有返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testApplyToEitherAsync() throws ExecutionException, InterruptedException {
	ExecutorService executorService = Executors.newCachedThreadPool();

	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	}, executorService);

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 20;
	}, executorService);

	CompletableFuture<Integer> completableFuture3 = completableFuture1.applyToEitherAsync(completableFuture2, (result) -> {
		log.info("回调函数获取到结果:" + result);
		log.info("回调函数执行中...");
		return result * 10;
	}, executorService);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:12:08.089 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:12:08.089 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:12:09.096 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:12:09.096 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到结果:10
22:12:09.096 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
22:12:10.096 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
22:12:10.096 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:100
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数入参为第一个完成的任务的返回结果,并带有返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testApplyToEitherAsyncException() throws ExecutionException, InterruptedException {
	ExecutorService executorService = Executors.newCachedThreadPool();

	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	}, executorService);

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		int a = 1 / 0;
		return 20;
	}, executorService);

	CompletableFuture<Integer> completableFuture3 = completableFuture1.applyToEitherAsync(completableFuture2, (result) -> {
		log.info("回调函数获取到结果:" + result);
		log.info("回调函数执行中...");
		return result * 10;
	}, executorService);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:12:40.922 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:12:40.928 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:12:41.928 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:12:41.929 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到结果:10
22:12:41.929 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testApplyToEitherAsyncException(CompletableFutureTest.java:966)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testApplyToEitherAsyncException$78(CompletableFutureTest.java:955)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
3.3.5 acceptEither/acceptEitherAsync

  acceptEither和acceptEitherAsync都是将两个异步任务组合后处理。回调函数会将第一个完成的任务的返回结果作为入参,但无返回值。如果两个任务有一个执行异常,则抛出异常。区别在于:acceptEither执行回调函数时会公用第一个完成的任务的线程,而acceptEitherAsync会使用不同的线程,并且acceptEitherAsync支持指定线程池。

  • acceptEither
/**
 * 任务1或任务2执行成功,再执行回调函数<br/>
 * 回调函数入参为第一个完成的任务的返回结果,无返回值
 * <p>
 * 回调函数和第一个完成的任务使用相同线程执行
 * </p>
 */
@Test
public void testAcceptEither() throws ExecutionException, InterruptedException {
	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	});

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 20;
	});

	CompletableFuture<Void> completableFuture3 = completableFuture1.acceptEither(completableFuture2, (result) -> {
		log.info("回调函数获取到结果:" + result);
		log.info("回调函数执行中...");
	});

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:15:07.135 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:15:07.135 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:15:08.141 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到结果:10
22:15:08.141 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:15:08.141 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
22:15:09.141 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
22:15:09.141 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数入参为第一个完成的任务的返回结果,无返回值
 * <p>
 * 回调函数和第一个完成的任务使用相同线程执行
 * </p>
 */
@Test
public void testAcceptEitherException() throws ExecutionException, InterruptedException {
	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	});

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		int a = 1 / 0;
		return 20;
	});

	CompletableFuture<Void> completableFuture3 = completableFuture1.acceptEither(completableFuture2, (result) -> {
		log.info("回调函数获取到结果:" + result);
		log.info("回调函数执行中...");
	});

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:18:56.628 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:18:56.628 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:18:57.633 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到结果:10
22:18:57.633 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:18:57.633 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testAcceptEitherException(CompletableFutureTest.java:1045)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testAcceptEitherException$84(CompletableFutureTest.java:1035)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
  • acceptEitherAsync
/**
 * 任务1或任务2执行成功,再执行回调函数<br/>
 * 回调函数入参为第一个完成的任务的返回结果,无返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testAcceptEitherAsync() throws ExecutionException, InterruptedException {
	ExecutorService executorService = Executors.newCachedThreadPool();

	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	}, executorService);

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 20;
	}, executorService);

	CompletableFuture<Void> completableFuture3 = completableFuture1.acceptEitherAsync(completableFuture2, (result) -> {
		log.info("回调函数获取到结果:" + result);
		log.info("回调函数执行中...");
	}, executorService);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:21:27.580 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:21:27.636 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:21:28.601 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:21:28.602 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到结果:10
22:21:28.602 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
22:21:29.637 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
22:21:29.637 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数入参为第一个完成的任务的返回结果,无返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testAcceptEitherAsyncException() throws ExecutionException, InterruptedException {
	ExecutorService executorService = Executors.newCachedThreadPool();

	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	}, executorService);

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		int a = 1 / 0;
		return 20;
	}, executorService);

	CompletableFuture<Void> completableFuture3 = completableFuture1.acceptEitherAsync(completableFuture2, (result) -> {
		log.info("回调函数获取到结果:" + result);
		log.info("回调函数执行中...");
	}, executorService);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:22:25.767 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:22:25.764 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:22:26.772 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:22:26.772 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数获取到结果:10
22:22:26.772 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testAcceptEitherAsyncException(CompletableFutureTest.java:1128)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testAcceptEitherAsyncException$90(CompletableFutureTest.java:1118)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
3.3.6 runAfterEither/runAfterEitherAsync

  runAfterEither和runAfterEitherAsync都是将两个异步任务组合后处理。回调函数无入参,也无返回值。如果两个任务有一个执行异常,则抛出异常。区别在于:runAfterEither执行回调函数时会公用第一个完成的任务的线程,而runAfterEitherAsync会使用不同的线程,并且runAfterEitherAsync支持指定线程池。

  • runAfterEither
/**
 * 任务1或任务2执行成功,再执行回调函数<br/>
 * 回调函数无入参,无返回值
 * <p>
 * 回调函数和第一个完成的任务使用相同线程执行
 * </p>
 */
@Test
public void testRunAfterEither() throws ExecutionException, InterruptedException {
	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	});

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 20;
	});

	CompletableFuture<Void> completableFuture3 = completableFuture1.runAfterEither(completableFuture2, () -> {
		log.info("回调函数执行中...");
	});

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:25:15.172 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:25:15.252 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:25:16.183 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
22:25:16.183 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:25:17.253 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
22:25:17.253 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数无入参,无返回值
 * <p>
 * 回调函数和第一个完成的任务使用相同线程执行
 * </p>
 */
@Test
public void testRunAfterEitherException() throws ExecutionException, InterruptedException {
	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	});

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		int a = 1 / 0;
		return 20;
	});

	CompletableFuture<Void> completableFuture3 = completableFuture1.runAfterEither(completableFuture2, () -> {
		log.info("回调函数执行中...");
	});

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:25:46.913 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:25:46.913 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:25:47.920 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
22:25:47.920 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testRunAfterEitherException(CompletableFutureTest.java:1205)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testRunAfterEitherException$96(CompletableFutureTest.java:1196)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
  • runAfterEitherAsync
/**
 * 任务1或任务2执行成功,再执行回调函数<br/>
 * 回调函数无入参,无返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testRunAfterEitherAsync() throws ExecutionException, InterruptedException {
	ExecutorService executorService = Executors.newCachedThreadPool();

	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	}, executorService);

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 20;
	}, executorService);

	CompletableFuture<Void> completableFuture3 = completableFuture1.runAfterEitherAsync(completableFuture2, () -> {
		log.info("回调函数执行中...");
	}, executorService);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:26:24.311 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:26:24.311 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:26:25.318 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:26:25.318 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...
22:26:26.318 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
22:26:26.318 [main] INFO com.c3stones.test.CompletableFutureTest - 回调函数返回结果:null
/**
 * 任务1执行成功,任务2执行失败,再执行回调函数<br/>
 * 回调函数无入参,无返回值
 * <p>
 * 提交给线程池,不同线程执行
 * </p>
 */
@Test
public void testRunAfterEitherAsyncException() throws ExecutionException, InterruptedException {
	ExecutorService executorService = Executors.newCachedThreadPool();

	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	}, executorService);

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		int a = 1 / 0;
		return 20;
	}, executorService);

	CompletableFuture<Void> completableFuture3 = completableFuture1.runAfterEitherAsync(completableFuture2, () -> {
		log.info("回调函数执行中...");
	}, executorService);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("回调函数返回结果:" + completableFuture3.get());
}

  控制台输出:

22:27:06.844 [pool-1-thread-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:27:06.844 [pool-1-thread-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:27:07.850 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:27:07.850 [pool-1-thread-3] INFO com.c3stones.test.CompletableFutureTest - 回调函数执行中...

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testRunAfterEitherAsyncException(CompletableFutureTest.java:1286)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testRunAfterEitherAsyncException$102(CompletableFutureTest.java:1277)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
3.3.7 allOf

  allOf将多个任务组合后处理,当所有任务都执行成功后,返回null,只要有一个任务执行异常,则抛出异常。

  • 任务1、任务2、任务3都执行成功
/**
 * 任务1、任务2、任务3都执行成功,返回null
 */
@Test
public void testAllOf() throws ExecutionException, InterruptedException {
	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	});

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 20;
	});

	CompletableFuture<Integer> completableFuture3 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 3 执行中...");
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 30;
	});

	CompletableFuture<Void> completableFuture = CompletableFuture.allOf(completableFuture1, completableFuture2, completableFuture3);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("任务 3 返回结果:" + completableFuture3.get());
	log.info("全部任务返回结果:" + completableFuture.get());
}

  控制台输出:

22:32:05.089 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:32:05.089 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:32:05.091 [ForkJoinPool.commonPool-worker-4] INFO com.c3stones.test.CompletableFutureTest - 任务 3 执行中...
22:32:06.095 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:32:07.096 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
22:32:08.095 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 3 返回结果:30
22:32:08.095 [main] INFO com.c3stones.test.CompletableFutureTest - 全部任务返回结果:null
  • 任务1、任务3执行成功,任务2执行异常
/**
 * 任务1、任务3执行成功,任务2执行异常
 */
@Test
public void testAllOfException() throws ExecutionException, InterruptedException {
	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	});

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		int a = 1 / 0;
		return 20;
	});

	CompletableFuture<Integer> completableFuture3 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 3 执行中...");
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 30;
	});

	CompletableFuture<Void> completableFuture = CompletableFuture.allOf(completableFuture1, completableFuture2, completableFuture3);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("任务 3 返回结果:" + completableFuture3.get());
	log.info("全部任务返回结果:" + completableFuture.get());
}

  控制台输出:

22:34:03.486 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:34:03.486 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:34:03.486 [ForkJoinPool.commonPool-worker-3] INFO com.c3stones.test.CompletableFutureTest - 任务 3 执行中...
22:34:04.499 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testAllOfException(CompletableFutureTest.java:1372)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testAllOfException$108(CompletableFutureTest.java:1355)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
3.3.8 anyOf

  anyOf将多个任务组合后处理,只要有一个任务执行成功,返回该任务结果,只要有一个任务执行异常,则抛出异常。

  • 任务1、任务2、任务3只要有一个任务执行成功,返回该任务结果
/**
 * 任务1、任务2、任务3只要有一个任务执行成功,返回该任务结果
 */
@Test
public void testAnyOf() throws ExecutionException, InterruptedException {
	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	});

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 20;
	});

	CompletableFuture<Integer> completableFuture3 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 3 执行中...");
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 30;
	});

	CompletableFuture<Object> completableFuture = CompletableFuture.anyOf(completableFuture1, completableFuture2, completableFuture3);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("任务 3 返回结果:" + completableFuture3.get());
	log.info("全部任务返回结果:" + completableFuture.get());
}

  控制台输出:

22:36:10.596 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:36:10.632 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:36:10.633 [ForkJoinPool.commonPool-worker-3] INFO com.c3stones.test.CompletableFutureTest - 任务 3 执行中...
22:36:11.605 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
22:36:12.632 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 2 返回结果:20
22:36:13.634 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 3 返回结果:30
22:36:13.634 [main] INFO com.c3stones.test.CompletableFutureTest - 全部任务返回结果:10
  • 任务1、任务3执行成功,任务2执行异常
/**
 * 任务1、任务3执行成功,任务2执行异常
 */
@Test
public void testAnyOfException() throws ExecutionException, InterruptedException {
	CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 1 执行中...");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 10;
	});

	CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 2 执行中...");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		int a = 1 / 0;
		return 20;
	});

	CompletableFuture<Integer> completableFuture3 = CompletableFuture.supplyAsync(() -> {
		log.info("任务 3 执行中...");
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 30;
	});

	CompletableFuture<Object> completableFuture = CompletableFuture.anyOf(completableFuture1, completableFuture2, completableFuture3);

	log.info("任务 1 返回结果:" + completableFuture1.get());
	log.info("任务 2 返回结果:" + completableFuture2.get());
	log.info("任务 3 返回结果:" + completableFuture3.get());
	log.info("全部任务返回结果:" + completableFuture.get());
}

  控制台输出:

22:36:44.307 [ForkJoinPool.commonPool-worker-2] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
22:36:44.307 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 2 执行中...
22:36:44.315 [ForkJoinPool.commonPool-worker-4] INFO com.c3stones.test.CompletableFutureTest - 任务 3 执行中...
22:36:45.316 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10

java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at com.c3stones.test.CompletableFutureTest.testAnyOfException(CompletableFutureTest.java:1459)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testAnyOfException$114(CompletableFutureTest.java:1442)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
3.4 获取结果
方法名称及参数 描述
T get() throws InterruptedException, ExecutionException 获取结果
T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 获取结果,超时自动退出
T getNow(T valueIfAbsent) 获取结果,未完成则返回传入的预期值
T join() 获取结果,和get()一样。区别在于:get()会抛出异常,join()不会抛出异常,出现异常时抛出未经检查( CompletionException)异常
boolean complete(T value) 设置任务完成,完成后所有阻塞方法获取到结果。如果未完成,则返回传入的预期值,一般非执行任务的线程调用
boolean completeExceptionally(Throwable ex) 设置任务完成,完成后所有阻塞方法获取到结果。如果未完成,则抛出传入的异常,一般非执行任务的线程调
  • get()
/**
 * 测试获取结果
 */
@Test
public void testGet() {
    // 记录开始时间
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 10;
    });

    try {
        log.info("任务 1 返回结果:" + completableFuture1.get());
    } catch (InterruptedException e) {
        log.error("中断异常");
    } catch (ExecutionException e) {
        log.error("执行异常");
    }

    stopWatch.stop();
    log.info("总耗时:" + stopWatch.getTotalTimeMillis() + " ms");
}

  控制台输出:

23:17:53.410 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
23:17:56.417 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:10
23:17:56.419 [main] INFO com.c3stones.test.CompletableFutureTest - 总耗时:3020 ms
  • get(long timeout, TimeUnit unit)
/**
 * 测试获取结果,超时自动退出
 */
@Test
public void testGetTimeout() {
    // 记录开始时间
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 10;
    });

    try {
        log.info("任务 1 返回结果:" + completableFuture1.get(2, TimeUnit.SECONDS));
    } catch (InterruptedException e) {
        log.error("中断异常");
    } catch (ExecutionException e) {
        log.error("执行异常");
    } catch (TimeoutException e) {
        log.error("超时异常");
    }

    stopWatch.stop();
    log.info("总耗时:" + stopWatch.getTotalTimeMillis() + " ms");
}

  控制台输出:

23:20:44.971 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
23:20:46.968 [main] ERROR com.c3stones.test.CompletableFutureTest - 超时异常
23:20:46.969 [main] INFO com.c3stones.test.CompletableFutureTest - 总耗时:2009 ms
  • getNow(T valueIfAbsent)
/**
 * 测试获取结果,未完成返回期预期
 */
@Test
public void testGetNow() {
    // 记录开始时间
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 10;
    });

    log.info("任务 1 返回结果:" + completableFuture1.getNow(-1));

    stopWatch.stop();
    log.info("总耗时:" + stopWatch.getTotalTimeMillis() + " ms");
}

  控制台输出:

23:21:13.897 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
23:21:13.897 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:-1
23:21:13.906 [main] INFO com.c3stones.test.CompletableFutureTest - 总耗时:20 ms
  • join()
/**
 * 测试获取结果,不会抛出异常
 */
@Test
public void testJoin() {
    // 记录开始时间
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int a = 1 / 0;
        return 10;
    });

    log.info("任务 1 返回结果:" + completableFuture1.join());

    stopWatch.stop();
    log.info("总耗时:" + stopWatch.getTotalTimeMillis() + " ms");
}

  控制台输出:

23:23:08.238 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...

java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero

	at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
	at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1592)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.lang.ArithmeticException: / by zero
	at com.c3stones.test.CompletableFutureTest.lambda$testJoin$119(CompletableFutureTest.java:1570)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
	... 5 more
  • complete(T value)
/**
 * 测试通知任务完成,未完成返回预期值
 */
@Test
public void testComplete() {
    // 记录开始时间
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int a = 1 / 0;
        return 10;
    });

    new Thread(() -> {
        completableFuture1.complete(-2);
    }, "其他线程").start();

    try {
        log.info("任务 1 返回结果:" + completableFuture1.get());
    } catch (InterruptedException e) {
        log.error("中断异常");
    } catch (ExecutionException e) {
        log.error("执行异常");
    }

    stopWatch.stop();
    log.info("总耗时:" + stopWatch.getTotalTimeMillis() + " ms");
}

  控制台输出:

23:23:55.594 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
23:23:55.594 [main] INFO com.c3stones.test.CompletableFutureTest - 任务 1 返回结果:-2
23:23:55.601 [main] INFO com.c3stones.test.CompletableFutureTest - 总耗时:17 ms
  • completeExceptionally(Throwable ex)
/**
 * 测试通知任务完成,未完成返回预期异常
 */
@Test
public void testCompleteExceptionally() {
    // 记录开始时间
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        log.info("任务 1 执行中...");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int a = 1 / 0;
        return 10;
    });

    new Thread(() -> {
        completableFuture1.completeExceptionally(new RuntimeException("提前完成异常"));
    }, "其他线程").start();

    try {
        log.info("任务 1 返回结果:" + completableFuture1.get());
    } catch (InterruptedException e) {
        log.error("中断异常");
    } catch (ExecutionException e) {
        if (e.getCause() instanceof RuntimeException) {
            log.error("预期异常:{}", e.getCause().getMessage());
        } else {
            log.error("非预期异常");
        }
    }

    stopWatch.stop();
    log.info("总耗时:" + stopWatch.getTotalTimeMillis() + " ms");
}

  控制台输出:

23:24:16.676 [ForkJoinPool.commonPool-worker-1] INFO com.c3stones.test.CompletableFutureTest - 任务 1 执行中...
23:24:16.676 [main] ERROR com.c3stones.test.CompletableFutureTest - 预期异常:提前完成异常
23:24:16.685 [main] INFO com.c3stones.test.CompletableFutureTest - 总耗时:21 ms

4. 项目地址

  thread-demo

posted @ 2023-03-28 16:56  C3Stones  阅读(444)  评论(0编辑  收藏  举报