CompletableFuture整理及拓展

本文详细介绍了CompletableFuture的创建、组合、异步操作、结果处理、线程池配置以及其优缺点,展示了如何使用它进行高效异步编程和异常管理。

思维导图

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对象进行合并

具体参考逻辑如下

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值