CompletableFuture 使用教程
创始人
2024-02-29 03:40:01
0

目录

  • 1. 创建异步任务
  • 2. 任务异步回调
    • 1. thenRun/thenRunAsync
    • 2. thenAccept/thenAcceptAsync
    • 3. thenApply/thenApplyAsync
    • 4. exceptionally
    • 5. whenComplete/whenCompleteAsync
    • 6. handle/handleAsync
  • 3. 多任务组合
    • 1. AND
    • 2. OR
    • 3. AllOf
    • 4. AnyOf
    • 5. thenCompose/thenComposeAsync
  • 注意点

CompletableFuture实现了CompletionStage接口和Future接口,CompletionStage是对Future的一个扩展,增加了异步回调、流式处理、多个Future组合处理的能力,使Java在处理多任务的协同工作时更加顺畅便利。

Future没有提供通知机制,Future是否执行完任务需要通过轮询isDone这个方法查询执行结果或者调用get()方法阻塞任务执行,CompletionStage解决了该问题,前一个任务执行成功后可以自动触发下一个任务的执行,中间无需等待。

1. 创建异步任务

supplyAsync方法

//使用默认内置线程池ForkJoinPool.commonPool(),根据supplier构建执行任务
public static  CompletableFuture supplyAsync(Supplier supplier)
//自定义线程,根据supplier构建执行任务
public static  CompletableFuture supplyAsync(Supplier supplier, Executor executor)

runAsync方法

//使用默认内置线程池ForkJoinPool.commonPool(),根据runnable构建执行任务
public static CompletableFuture runAsync(Runnable runnable) 
//自定义线程,根据runnable构建执行任务
public static CompletableFuture runAsync(Runnable runnable,  Executor executor)
  • supplyAsync执行CompletableFuture任务,支持返回值
  • runAsync执行CompletableFuture任务,没有返回值。
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) {CompletableFuture runFuture =CompletableFuture.runAsync(() -> userService.compute("runAsync"), fishExecutor);CompletableFuture supplyFuture =CompletableFuture.supplyAsync(() -> userService.compute("supplyAsync"), fishExecutor);System.out.println(runFuture.join());System.out.println(supplyFuture.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}}
}

join与get的区别

  • 相同点
    1.join()和get()方法都是用来获取CompletableFuture异步之后的返回值

  • 不同点
    1.join()方法抛出的是RuntimeException异常,不需要特殊处理
    2.get()方法抛出的是需要手动处理的异常,例如ExecutionException, InterruptedException,需要抛出或者try-catch

  • 结果打印

16:45:22.054 [fish] INFO com.example.mavendemo.Test$UserService - runAsync
16:45:22.054 [fish] INFO com.example.mavendemo.Test$UserService - supplyAsync
null
supplyAsync

2. 任务异步回调

1. thenRun/thenRunAsync

public CompletableFuture thenRun(Runnable action);
public CompletableFuture thenRunAsync(Runnable action);
  • thenRun/thenRunAsync作用是做完第一个任务后,再做第二个任务(Runnable action)。前一个任务执行结束后,执行回调方法(Runnable action);但是两个任务之间没有参数传递,第二个任务也没有返回值
  • thenRun 和 thenRunAsync 的区别:

thenRun执行第二个任务的线程池和第一个任务是同一个,或者thenRunAsync传入的线程池
thenRunAsync执行第二个任务使用的是ForkJoin线程池,或者你传入的线程池

    public CompletableFuture thenRun(Runnable action) {return uniRunStage(null, action);}public CompletableFuture thenRunAsync(Runnable action) {return uniRunStage(asyncPool, action);}public CompletableFuture thenRunAsync(Runnable action, Executor executor) {return uniRunStage(screenExecutor(executor), action);}    
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test2 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));public static void main(String[] args) {CompletableFuture supplyFuture =CompletableFuture.supplyAsync(() -> userService.compute("第一个任务"), fishExecutor);CompletableFuture voidCompletableFuture1 = supplyFuture.thenRun(() -> userService.noResult("第二个任务"));CompletableFuture voidCompletableFuture2 = supplyFuture.thenRunAsync(() -> userService.noResult("第三个任务"));System.out.println(voidCompletableFuture1.join());System.out.println(voidCompletableFuture2.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}public void noResult(String message) {log.info(message);}}
}
  • 打印,第二个任务和第一个任务使用fish线程
16:45:48.526 [fish] INFO com.example.mavendemo.Test2$UserService - 第一个任务
16:45:48.529 [fish] INFO com.example.mavendemo.Test2$UserService - 第二个任务
null
16:45:48.530 [ForkJoinPool.commonPool-worker-9] INFO com.example.mavendemo.Test2$UserService - 第三个任务
null
  • 加入第四任务,在看任务使用的线程
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test2 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static ExecutorService catExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "cat"));static UserService userService = new UserService();public static void main(String[] args) {CompletableFuture supplyFuture =CompletableFuture.supplyAsync(() -> userService.compute("第一个任务"), fishExecutor);CompletableFuture voidCompletableFuture1 = supplyFuture.thenRun(() -> userService.noResult("第二个任务"));CompletableFuture voidCompletableFuture2 = supplyFuture.thenRunAsync(() -> userService.noResult("第三个任务"));CompletableFuture voidCompletableFuture3 =supplyFuture.thenRunAsync(() -> userService.noResult("第四个任务"), catExecutor);System.out.println(voidCompletableFuture1.join());System.out.println(voidCompletableFuture2.join());System.out.println(voidCompletableFuture3.join());fishExecutor.shutdown();catExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}public void noResult(String message) {log.info(message);}}
}
  • 打印,第二个任务和第四个任务使用cat线程,第三个任务使用ForkJoinPool线程
16:47:34.132 [fish] INFO com.example.mavendemo.Test2$UserService - 第一个任务
16:47:34.134 [cat] INFO com.example.mavendemo.Test2$UserService - 第四个任务
16:47:34.134 [cat] INFO com.example.mavendemo.Test2$UserService - 第二个任务
null
16:47:34.135 [ForkJoinPool.commonPool-worker-9] INFO com.example.mavendemo.Test2$UserService - 第三个任务
null
null

2. thenAccept/thenAcceptAsync

  • 第一个任务执行结束后,执行第二个回调方法任务,会将第一个任务的执行结果作为入参,传递到回调方法中,但回调方法没有返回值
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test3 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) {CompletableFuture supplyFuture =CompletableFuture.supplyAsync(() -> userService.compute("这是第一个任务"), fishExecutor);CompletableFuture voidCompletableFuture1 =supplyFuture.thenAccept((a) -> userService.noResult("传入了前一个任务的结果:" + a));CompletableFuture voidCompletableFuture2 =supplyFuture.thenAcceptAsync((a) -> userService.noResult("传入了前一个任务的结果:" + a));System.out.println(voidCompletableFuture1.join());System.out.println(voidCompletableFuture2.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}public void noResult(String message) {log.info(message);}}
}
  • 打印
17:01:09.637 [fish] INFO com.example.mavendemo.Test3$UserService - 这是第一个任务
17:01:09.639 [fish] INFO com.example.mavendemo.Test3$UserService - 传入了前一个任务的结果:这是第一个任务
17:01:09.639 [ForkJoinPool.commonPool-worker-9] INFO com.example.mavendemo.Test3$UserService - 传入了前一个任务的结果:这是第一个任务
null
null

3. thenApply/thenApplyAsync

  • 第一个任务执行完成后,执行第二个任务的回调方法,将第一个任务的执行结果作为入参,传递到回调方法中,而且回调方法有返回值
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test4 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) {CompletableFuture supplyFuture =CompletableFuture.supplyAsync(() -> userService.compute("这是第一个任务"), fishExecutor);CompletableFuture voidCompletableFuture1 =supplyFuture.thenApply((a) -> userService.compute("传入了前一个任务的结果:" + a));CompletableFuture voidCompletableFuture2 =supplyFuture.thenApplyAsync((a) -> userService.compute("传入了前一个任务的结果:" + a));System.out.println(voidCompletableFuture1.join());System.out.println(voidCompletableFuture2.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}public void noResult(String message) {log.info(message);}}
}
  • 打印
17:06:08.946 [fish] INFO com.example.mavendemo.Test4$UserService - 这是第一个任务
17:06:08.948 [fish] INFO com.example.mavendemo.Test4$UserService - 传入了前一个任务的结果:这是第一个任务
传入了前一个任务的结果:这是第一个任务
17:06:08.948 [ForkJoinPool.commonPool-worker-9] INFO com.example.mavendemo.Test4$UserService - 传入了前一个任务的结果:这是第一个任务
传入了前一个任务的结果:这是第一个任务

4. exceptionally

  • 任务执行异常时,执行回调方法;并且将抛出的异常作为参数,传到回调方法
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test5 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) {CompletableFuture supplyFuture =CompletableFuture.supplyAsync(() -> userService.exceptionMethod("这是第一个任务"), fishExecutor);CompletableFuture exceptionally = supplyFuture.exceptionally(o -> userService.catchException(o));System.out.println(exceptionally.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String exceptionMethod(String message) {log.info(message);throw new RuntimeException(message);}public String catchException(Object o) {RuntimeException e = (RuntimeException)o;log.error("{}", e);return e.getMessage();}}
}
  • 打印
17:37:53.901 [fish] INFO com.example.mavendemo.Test5$UserService - 这是第一个任务
17:37:53.907 [fish] ERROR com.example.mavendemo.Test5$UserService - {}
java.util.concurrent.CompletionException: java.lang.RuntimeException: 这是第一个任务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.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.RuntimeException: 这是第一个任务at com.example.mavendemo.Test5$UserService.exceptionMethod(Test5.java:27)at com.example.mavendemo.Test5.lambda$main$1(Test5.java:16)at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)... 3 common frames omitted
java.lang.RuntimeException: 这是第一个任务

5. whenComplete/whenCompleteAsync

  • 第一个任务执行结束后,执行第二个回调方法任务,把上一级任务执行的结果和异常信息作为入参传入回调方法;并且whenComplete方法返回的CompletableFuture的result是上个任务的结果。
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test6 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) {CompletableFuture supplyFuture =CompletableFuture.supplyAsync(() -> userService.compute("这是第一个任务"), fishExecutor);CompletableFuture voidCompletableFuture1 =supplyFuture.whenComplete((a,throwable) -> userService.compute("传入了前一个任务的结果:" + a));CompletableFuture voidCompletableFuture2 =supplyFuture.whenCompleteAsync((a,throwable) -> userService.compute("传入了前一个任务的结果:" + a));System.out.println(voidCompletableFuture1.join());System.out.println(voidCompletableFuture2.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}public void noResult(String message) {log.info(message);}}
}
  • 打印
17:49:36.135 [fish] INFO com.example.mavendemo.Test6$UserService - 这是第一个任务
17:49:36.137 [fish] INFO com.example.mavendemo.Test6$UserService - 传入了前一个任务的结果:这是第一个任务
这是第一个任务
17:49:36.137 [ForkJoinPool.commonPool-worker-9] INFO com.example.mavendemo.Test6$UserService - 传入了前一个任务的结果:这是第一个任务
这是第一个任务

6. handle/handleAsync

  • 第一个任务执行结束后,执行第二个回调方法任务,把上一级任务执行的结果和异常信息作为入参传入回调方法;并且whenComplete方法返回的CompletableFuture的result是回调方法的结果。
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test7 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) {CompletableFuture supplyFuture =CompletableFuture.supplyAsync(() -> userService.compute("这是第一个任务"), fishExecutor);CompletableFuture voidCompletableFuture1 =supplyFuture.handle((a,throwable) -> userService.compute("传入了前一个任务的结果:" + a));CompletableFuture voidCompletableFuture2 =supplyFuture.handleAsync((a,throwable) -> userService.compute("传入了前一个任务的结果:" + a));System.out.println(voidCompletableFuture1.join());System.out.println(voidCompletableFuture2.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}public void noResult(String message) {log.info(message);}}
}
  • 打印
17:52:20.197 [fish] INFO com.example.mavendemo.Test7$UserService - 这是第一个任务
17:52:20.199 [fish] INFO com.example.mavendemo.Test7$UserService - 传入了前一个任务的结果:这是第一个任务
传入了前一个任务的结果:这是第一个任务
17:52:20.199 [ForkJoinPool.commonPool-worker-9] INFO com.example.mavendemo.Test7$UserService - 传入了前一个任务的结果:这是第一个任务
传入了前一个任务的结果:这是第一个任务

3. 多任务组合

1. AND

  • thenCombine / thenAcceptBoth / runAfterBoth都表示将两个CompletableFuture组合起来,只有这两个都正常执行结束,才会执行回调任务。
  • 区别在于:
    thenCombine/thenCombineAsync: 会将两个任务的执行结果作为入参,传到指定方法中,且有返回值
    thenAcceptBoth/thenAcceptBothAsync: 会将两个任务的执行结果作为入参,传到指定方法中,且无返回值
    runAfterBoth/runAfterBothAsync: 不会把执行结果当做入参,且没有返回值。
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test8 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) {CompletableFuture first =CompletableFuture.supplyAsync(() -> userService.compute("这是第一个任务"), fishExecutor);CompletableFuture second =CompletableFuture.supplyAsync(() -> userService.compute("这是第二个任务"), fishExecutor);CompletableFuture thenCombine = first.thenCombine(second, (s, s2) -> userService.combine(s, s2));System.out.println(thenCombine.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}public String combine(String first, String second) {log.info("这是combine方法");return first + second;}}
}
  • 打印
09:49:38.621 [fish] INFO com.example.mavendemo.Test8$UserService - 这是第二个任务
09:49:38.621 [fish] INFO com.example.mavendemo.Test8$UserService - 这是第一个任务
09:49:38.624 [fish] INFO com.example.mavendemo.Test8$UserService - 这是combine方法
这是第一个任务这是第二个任务

2. OR

  • applyToEither / acceptEither / runAfterEither 都表示:将两个CompletableFuture组合起来,只要其中一个执行结束,就会执行回调任务。
  • 区别在于:
    applyToEither/applyToEitherAsync: 会将已经执行完成的任务的结果作为入参,传到指定方法中,且有返回值
    acceptEither/acceptEitherAsync: 会将已经执行完成的任务的结果作为入参,传到指定方法中,且无返回值
    runAfterEither/runAfterEitherAsync: 不会把执行结果当做入参,且没有返回值。
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test9 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) {CompletableFuture first =CompletableFuture.supplyAsync(() -> userService.compute("这是第一个任务"), fishExecutor);CompletableFuture second =CompletableFuture.supplyAsync(() -> userService.compute("这是第二个任务"), fishExecutor);CompletableFuture applyToEither = first.applyToEither(second, s -> userService.either(s));System.out.println(applyToEither.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}public String either(String result) {log.info("这是either方法");return result;}}
}
  • 打印
10:02:51.523 [fish] INFO com.example.mavendemo.Test9$UserService - 这是第一个任务
10:02:51.523 [fish] INFO com.example.mavendemo.Test9$UserService - 这是第二个任务
10:02:51.526 [fish] INFO com.example.mavendemo.Test9$UserService - 这是either方法
这是第一个任务
  • 也可能打印
10:03:50.381 [fish] INFO com.example.mavendemo.Test9$UserService - 这是第二个任务
10:03:50.381 [fish] INFO com.example.mavendemo.Test9$UserService - 这是第一个任务
10:03:50.383 [fish] INFO com.example.mavendemo.Test9$UserService - 这是either方法
这是第二个任务

3. AllOf

  • 所有任务都执行完成后,才执行 allOf 返回的CompletableFuture。如果任意一个任务异常,allOf的CompletableFuture执行get或join方法,会抛出异常;如果都是正常执行,则返回null。
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test10 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) {CompletableFuture first =CompletableFuture.supplyAsync(() -> userService.compute("这是第一个任务"), fishExecutor);CompletableFuture second =CompletableFuture.supplyAsync(() -> userService.error("这是第二个任务"), fishExecutor);CompletableFuture allOfFuture =CompletableFuture.allOf(first, second).whenComplete((unused, throwable) -> {System.out.println(unused);System.out.println(throwable.getMessage());System.out.println("finish");});System.out.println(allOfFuture.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}public String error(String message) {log.info(message);throw new RuntimeException("出错了");}}
}
  • 打印
10:41:43.120 [fish] INFO com.example.mavendemo.Test10$UserService - 这是第二个任务
10:41:43.120 [fish] INFO com.example.mavendemo.Test10$UserService - 这是第一个任务
null
java.lang.RuntimeException: 出错了
finish
Exception in thread "main" java.util.concurrent.CompletionException: java.lang.RuntimeException: 出错了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.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.RuntimeException: 出错了at com.example.mavendemo.Test10$UserService.computeError(Test10.java:40)at com.example.mavendemo.Test10.lambda$main$2(Test10.java:18)at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)... 3 more

4. AnyOf

  • 任意一个任务执行完,就执行anyOf返回的CompletableFuture。如果执行get或join方法,返回执行完任务的结果。
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test11 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture first =CompletableFuture.supplyAsync(() -> userService.compute("这是第一个任务"), fishExecutor);CompletableFuture second =CompletableFuture.supplyAsync(() -> userService.compute("这是第二个任务"), fishExecutor);CompletableFuture anyOfFuture =CompletableFuture.anyOf(second, first).whenComplete((unused, throwable) -> {System.out.println(unused);System.out.println("finish");});System.out.println(anyOfFuture.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public String compute(String message) {log.info(message);return message;}}
} 
  • 打印
13:15:46.529 [fish] INFO com.example.mavendemo.Test11$UserService - 这是第二个任务
13:15:46.529 [fish] INFO com.example.mavendemo.Test11$UserService - 这是第一个任务
这是第二个任务
finish
这是第二个任务

5. thenCompose/thenComposeAsync

  • 在一个任务执行完成后,将该任务的执行结果作为入参,传到指定的方法去执行,该方法会返回一个新的CompletableFuture实例。
package com.example.mavendemo;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import lombok.extern.slf4j.Slf4j;public class Test12 {static ExecutorService fishExecutor = Executors.newCachedThreadPool((r) -> new Thread(r, "fish"));static UserService userService = new UserService();public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture first =CompletableFuture.supplyAsync(() -> userService.number("996"), fishExecutor);CompletableFuture thenCompose = first.thenCompose(s -> CompletableFuture.supplyAsync(() -> userService.compute("这是第二个任务,接收到的入参是:" + s), fishExecutor));System.out.println(thenCompose.join());fishExecutor.shutdown();}@Slf4jstatic class UserService {public Integer number(String number) {log.info(number);return Integer.valueOf(number);}public String compute(String message) {log.info(message);return message;}}
}
  • 打印
13:57:16.096 [fish] INFO com.example.mavendemo.Test12$UserService - 996
13:57:16.098 [fish] INFO com.example.mavendemo.Test12$UserService - 这是第二个任务,接收到的入参是:996
这是第二个任务,接收到的入参是:996

注意点

  1. 如果任务执行发生异常,需要调用get()或join()获取返回值,才能获取异常信息;或者使用try…catch…或者使用exceptionally方法。

  2. CompletableFuture的get()方法是阻塞的,如果使用它来获取异步调用的返回值,最好添加超时时间,例如get(10, TimeUnit.SECONDS)

  3. 推荐使用自定义线程池,这样可以根据需要优化线程池配置

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...