了解CompletableFuture【1】介绍
1)简单的任务,用Future获取结果还好,但我们并行提交的多个异步任务,往往并不是独立的,很多时候业务逻辑处理存在串行[依赖]、并行、聚合的关系 。如果要我们手动用 Fueture 实现,是非常麻烦的 。
2)CompletableFuture是Future接口的扩展和增强 。CompletableFuture实现了Future接口,并在此基础上进行了丰富地扩展,完美地弥补了Future上述的种种问题 。更为重要的是,CompletableFuture实现了对任务的编排能力 。借助这项能力,我们可以轻松地组织不同任务的运行顺序、规则以及方式 。从某种程度上说,这项能力是它的核心能力 。而在以往,虽然通过CountDownLatch等工具类也可以实现任务的编排,但需要复杂的逻辑处理,不仅耗费精力且难以维护 。
3)CompletableFuture除了实现Future接口还实现了CompletionStage接口 。
4)CompletionStage接口: 执行某一个阶段,可向下执行后续阶段 。异步执行,默认线程池是ForkJoinPool.commonPool() 。
【2】常用方法
1)描述依赖关系:
1.thenApply() 把前面异步任务的结果,交给后面的Function
2.thenCompose()用来连接两个有依赖关系的任务,结果由第二个任务返回
2)描述and聚合关系:
1.thenCombine:任务合并,有返回值
2.thenAccepetBoth:两个任务执行完成后,将结果交给thenAccepetBoth消耗,无返回值 。
3.runAfterBoth:两个任务都执行完成后,执行下一步操作(Runnable) 。
3)描述or聚合关系:
1.applyToEither:两个任务谁执行的快,就使用那一个结果,有返回值 。
2.acceptEither: 两个任务谁执行的快,就消耗那一个结果,无返回值 。
3.runAfterEither: 任意一个任务执行完成,进行下一步操作(Runnable) 。
4)并行执行:
1.CompletableFuture类自己也提供了anyOf()和allOf()用于支持多个CompletableFuture并行执行
【3】创建异步操作
1)CompletableFuture 提供了四个静态方法来创建一个异步操作:
public static CompletableFuture<Void> runAsync(Runnable runnable)public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)2)这四个方法区别在于:
1.runAsync 方法以Runnable函数式接口类型为参数,没有返回结果,supplyAsync 方法Supplier函数式接口类型为参数,返回结果类型为U;Supplier 接口的 get() 方法是有返回值的(会阻塞) 。
2.没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码 。如果指定线程池,则使用指定的线程池运行 。
3.默认情况下 CompletableFuture 会使用公共的 ForkJoinPool 线程池,这个线程池默认创建的线程数是 CPU 的核数(也可以通过 JVM option:-Djava.util.concurrent.ForkJoinPool.common.parallelism 来设置 ForkJoinPool 线程池的线程数) 。如果所有 CompletableFuture 共享一个线程池,那么一旦有任务执行一些很慢的 I/O 操作,就会导致线程池中所有线程都阻塞在 I/O 操作上,从而造成线程饥饿,进而影响整个系统的性能 。所以,强烈建议你要根据不同的业务类型创建不同的线程池,以避免互相干扰 。
3)supplyAsync的两种获取结果的方法join&get
1.join()和get()方法都是用来获取CompletableFuture异步之后的返回值 。join()方法抛出的是uncheck异常(即未经检查的异常),不会强制开发者抛出 。get()方法抛出的是经过检查的异常,ExecutionException, InterruptedException 需要用户手动处理(抛出或者 try catch)
经验总结扩展阅读
- Go的网络编程详解
- gorm中的关联操作详解
- Go中的闭包、递归
- liunx之expect操作详解
- 条件期望:Conditional Expectation 举例详解之入门之入门之草履虫都说听懂了
- 深入理解AQS--jdk层面管程实现【管程详解的补充】
- 从缓存入门到并发编程三要素详解 Java中 volatile 、final 等关键字解析案例
- 补充部分---ScheduledThreadPoolExecutor类分析 线程池底层原理详解与源码分析
- Redis高并发分布式锁详解
- 5种分布式ID生成方案 分布式ID详解

 
   
   
   
   
   
   
   
  