思维导图
CompletableFuture使用及api介绍
一.创建CompletableFuture对象
//异步执行一个有返回值的任务
CompletableFuture demoFuture1 = CompletableFuture.supplyAsync(()->{ return "ss";});
//异步执行一个无返回值的任务
CompletableFuture demoFuture2 = CompletableFuture.runAsync(()->{System.out.println("ss");});
//创建一个已经完成的CompletableFuture对象
CompletableFuture demoFuture3 = CompletableFuture.completedFuture("ss");
// 创建一个未完成的CompletableFuture对象
CompletableFuture demoFuture4 = new CompletableFuture();
二.组合CompletableFuture对象
//在CompletableFuture对象上执行一个函数,并返回一个新的带返回值的CompletableFuture对象
CompletableFuture<String> demoFuture1 = CompletableFuture.supplyAsync(()-> "ss");
CompletableFuture demoFuture2 = demoFuture1.thenApply((String s)->{ return s+"t";});
//在CompletableFuture对象上执行一个消费者,并返回一个新的CompletableFuture对象
CompletableFuture demoFuture3 = demoFuture1.thenAccept((String s)->{ System.out.println(s);});
//在CompletableFuture对象上执行一个Runnable,并返回一个新的CompletableFuture对象
CompletableFuture demoFuture4 = demoFuture1.thenRun(()->{ System.out.println("ss");});
//在CompletableFuture对象上执行一个函数,返回一个新的CompletableFuture对象 和thenApply很像,但是需要自己手动返回CompletableFuture对象
CompletableFuture<String> demoFuture5 = demoFuture1.thenCompose((String s)->{
System.out.println(s);
return new CompletableFuture();
});
//将两个CompletableFuture对象的结果组合起来,并执行一个函数,返回一个新的
CompletableFuture对象demoFuture1.thenCombine(demoFuture5,(t,s)->{ return s+t;});
//allOf(CompletableFuture... cfs):等待所有的CompletableFuture对象执行完成
CompletableFuture allofCompletableFuture = CompletableFuture.allOf(demoFuture1,demoFuture2);
//anyOf(CompletableFuture... cfs):等待任意一个CompletableFuture对象执行完成
CompletableFuture anyofCompletableFuture = CompletableFuture.anyOf(demoFuture1,demoFuture2);
//acceptEither(CompletionStage other, Consumer action):两个CompletableFuture对象任意一个完成后执行指定的消费者
CompletableFuture acceptEitherFuture = demoFuture1.acceptEither(demoFuture2,(s)->{ System.out.println(s);});
//applyToEither(CompletionStage other, Function fn):两个CompletableFuture对象任意一个完成后执行指定的函数,并返回一个新的CompletableFuture对象
CompletableFuture applyToEitherFuture = demoFuture1.applyToEither(demoFuture2,(s)->{ return s;});
//runAfterBoth(CompletionStage other, Runnable action):两个CompletableFuture对象都完成后执行指定的Runnable
CompletableFuture runAfterBothFuture = demoFuture1.runAfterBoth(demoFuture2,()->{ System.out.println("ss");});
//runAfterEither(CompletionStage other, Runnable action):两个CompletableFuture对象任意一个完成后执行指定的Runnable
CompletableFuture runAfterEitherFuture = demoFuture1.runAfterEither(demoFuture2,()->{ System.out.println("ss");});
//thenAcceptBoth(CompletionStage other, BiConsumer action):将两个CompletableFuture对象的结果组合起来,并执行一个消费者
CompletableFuture thenAcceptBothFuture = demoFuture1.thenAcceptBoth(demoFuture2,(s,t)->{ System.out.println(s); System.out.println(t);});
三.处理CompletableFuture对象的结果
//get():获取CompletableFuture对象的结果,如果任务还未完成,则会阻塞等待
CompletableFuture<String> demoFuture1 = CompletableFuture.supplyAsync(()-> "ss");
try {
demoFuture1.get();
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//get(long timeout, TimeUnit unit):获取CompletableFuture对象的结果,如果任务还未完成,则会阻塞等待一段时间
try {
demoFuture1.get(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
//join():获取CompletableFuture对象的结果,如果任务还未完成,则会一直阻塞,和get的区别在于不抛出异常,get方法需要手动捕获
demoFuture1.join();
//cancel(boolean mayInterruptIfRunning):尝试取消CompletableFuture对象的执行
demoFuture1.cancel(true);
//isCancelled():判断CompletableFuture对象是否被取消
demoFuture1.isCancelled();
//isCompletedExceptionally():判断CompletableFuture对象是否执行异常
demoFuture1.isCompletedExceptionally();
//isDone():判断CompletableFuture对象是否执行完成
demoFuture1.isDone();
四.结果异常处理
//exceptionally(Function fn):处理CompletableFuture对象执行过程中的异常
CompletableFuture<String> demoFuture1 = CompletableFuture.supplyAsync(()-> "ss");
demoFuture1.exceptionally((Throwable e)->{
System.out.println(e.getMessage());
return "s";
});
//handle(BiFunction fn):处理CompletableFuture对象执行过程中的异常,同时处理正常结果
demoFuture1.handle((t,e)->{
System.out.println(t.toUpperCase());
System.out.println(e.getMessage());
return "s";
});
五.指定业务线程池
private static final Executor executor = TtlExecutors.getTtlExecutor(new ThreadPoolExecutor(1,1,3000, TimeUnit.MILLISECONDS,new ArrayBlockingQueue(100)));
//使用指定的线程池执行异步任务,不指定的话默认走ForkJoinPool线程池
//默认ForkJoinPool线程池,ForkJoinPool里面的线程都是daemon线程,非daemon线程都结束后,虚拟机也就退出了。
//如果需要执行较长时间或执行内容比较重要不希望被中断而导致数据不一致的话,那就自己传一个Executor吧
CompletableFuture<String> demoFuture1 = CompletableFuture.supplyAsync(()-> "ss",executor);
CompletableFuture demoFuture2 = CompletableFuture.runAsync(()->{ System.out.println("s");},executor);
源码介绍
一.CompletionStage
CompletionStage可以用于构建复杂的异步计算流水线,通过串行、并行、组合等方式来处理异步计算的结果。
CompletableFuture实现了接口CompletionStage来处理组合和编排CompletableFuture对象之类操作。
如下图,包括等等这些操作。
二.FunctionalInterface
FunctionalInterface是Java8引入的一个新特性,用于表示一个接口是函数式接口。函数式接口是只包含一个抽象方法的接口,可以被Lambda表达式所实现。
FunctionalInterface的特点: - 只能包含一个抽象方法,可以有多个默认方法和静态方法。
CompletionStage 组合CompletableFuture对象时大量使用FunctionalInterface
例如下面的函数式接口 就是CompletionStage的thenAcceptBoth的方法入参。
三.ForkJoinPool
CompletableFuture的任务提交的时候默认使用ForkJoinPool线程池来处理。
它是一个特殊的线程池,可以充分利用多核处理器的性能,提高并发性能,内部使用工作窃取算法来提高任务的执行效率。
ForkJoinPool可以将一个大任务拆分成多个小任务,并行执行这些小任务,最后合并结果。
四.Completion
如下图,CompletableFuture成员变量,Completion对象stack,这是一个CAS实现的无锁并发栈,每个链式调用的任务会被压入这个栈
如下图,本身Completion的成员变量Completion,next指向,并继承ForkJoinTask,默认的线程池是ForkJoinPool
通过这两个特性来进行链式调用,可以参考这篇文章 深入理解JDK8新特性CompletableFuture-阿里云开发者社区
CompletableFuture优缺点
优点
1. 异步编程:CompletableFuture提供了一种简单且强大的方式来进行异步编程,可以避免阻塞线程,提高系统的并发性能。
2. 链式操作:CompletableFuture支持链式调用,可以通过一系列的操作来组合多个CompletableFuture,实现复杂的异步任务。
3. 异常处理:CompletableFuture提供了异常处理的机制,可以通过exceptionally()、handle()等方法来处理异常,保证程序的健壮性。
4. 高度可定制性:CompletableFuture提供了丰富的方法来定制异步任务的执行方式,可以设置超时时间、执行顺序、并发级别等。
缺点
1. 学习成本高:CompletableFuture的使用相对复杂,需要掌握一些异步编程的概念和技巧,对于初学者来说学习成本较高。
2. 可读性差:由于CompletableFuture支持链式调用,代码可能会变得冗长和难以理解,特别是当有多个异步任务需要组合时。
3. 线程资源占用:CompletableFuture在执行异步任务时会占用一定的线程资源,如果不合理地使用CompletableFuture,可能会导致线程资源的浪费。
CompletableFuture的拓展
1.如何支持将多个超过两个以上的CompletableFuture对象进行合并
具体参考逻辑如下