第二部分:并发工具类24->CompletableFuture,异步编程没那么难

1.异步编程

串行操作并行化,涉及到异步化

异步化,是并行方案得以实施的接触,利用多线程优化性能这个核心方案来实施的基础。

jdk1.8提供了CompletableFuture支持异步编程

2.CompletableFuture 核心优势

烧水泡茶,3个任务
任务1,洗水壶,烧开水
任务2,洗茶壶,洗茶杯,拿茶叶
任务3,泡茶

任务3需要等待任务1,和任务2都完成才可以执行

image

有一些没有见过的方法,
runAsync()
supplyAsync()
thenCombine()

特点:
1.无需手工维护线程,没有手工维护线程的工作,给任务分配线程不需要我们关注
2.语意清晰,f3 = f1.thenCombine(f2,() -> {})能够清晰表述“任务3等待任务1和任务2都完成后才开始”
3.代码简练,专注业务逻辑


//任务1:洗水壶->烧开水
CompletableFuture<Void> f1 = 
  CompletableFuture.runAsync(()->{
  System.out.println("T1:洗水壶...");
  sleep(1, TimeUnit.SECONDS);

  System.out.println("T1:烧开水...");
  sleep(15, TimeUnit.SECONDS);
});
//任务2:洗茶壶->洗茶杯->拿茶叶
CompletableFuture<String> f2 = 
  CompletableFuture.supplyAsync(()->{
  System.out.println("T2:洗茶壶...");
  sleep(1, TimeUnit.SECONDS);

  System.out.println("T2:洗茶杯...");
  sleep(2, TimeUnit.SECONDS);

  System.out.println("T2:拿茶叶...");
  sleep(1, TimeUnit.SECONDS);
  return "龙井";
});
//任务3:任务1和任务2完成后执行:泡茶
CompletableFuture<String> f3 = 
  f1.thenCombine(f2, (__, tf)->{
    System.out.println("T1:拿到茶叶:" + tf);
    System.out.println("T1:泡茶...");
    return "上茶:" + tf;
  });
//等待任务3执行结果
System.out.println(f3.join());

void sleep(int t, TimeUnit u) {
  try {
    u.sleep(t);
  }catch(InterruptedException e){}
}
// 一次执行结果:
T1:洗水壶...
T2:洗茶壶...
T1:烧开水...
T2:洗茶杯...
T2:拿茶叶...
T1:拿到茶叶:龙井
T1:泡茶...
上茶:龙井

3.CompletableFuture对象

创建

//使用默认线程池
static CompletableFuture<Void> 
  runAsync(Runnable runnable)
static <U> CompletableFuture<U> 
  supplyAsync(Supplier<U> supplier)
//可以指定线程池  
static CompletableFuture<Void> 
  runAsync(Runnable runnable, Executor executor)
static <U> CompletableFuture<U> 
  supplyAsync(Supplier<U> supplier, Executor executor)  

runAsync(Runnable runnable)
supplyAsync(Supplier supplier)

区别是什么?Runnable接口的run方法没有返回值,Supplier的get方法是有返回值的,其余额外的是带线程池传递
默认不传的话用的是默认ForkJoinPool线程池,线程数默认是cpu核数
建议根据不同业务类型创建不同的线程池,以免相互干扰

注意事项:
创建完CompletableFuture对象之后,自动异步执行runnable.run()方法或者supplier.get()方法

这也可以通过future来获取执行结果和判断线程是否执行结束。

4.CompletableFuture的高级功能

CompletableFuture类实现了CompletionStage接口,有40多个方法

CompletionStage接口

大概说明:
串行关系

并行关系
image
汇聚关系
image
异常处理

前面提到的f3 = f1.thenCombine(f2, () -> {})描述的就是汇聚关系,说白了就是AND聚合关系
f3是等f1,f2都执行完,才执行;当然还是or关系,只有其中1个执行完就可以执行

4.1 串行关系

thenApply,thenAccept,thenRun,thenCompose四个接口


CompletionStage<R> thenApply(fn);
CompletionStage<R> thenApplyAsync(fn);
CompletionStage<Void> thenAccept(consumer);
CompletionStage<Void> thenAcceptAsync(consumer);
CompletionStage<Void> thenRun(action);
CompletionStage<Void> thenRunAsync(action);
CompletionStage<R> thenCompose(fn);
CompletionStage<R> thenComposeAsync(fn);

4.2 and 汇聚关系

CompletionStage applyToEither(other, fn);
CompletionStage applyToEitherAsync(other, fn);
CompletionStage acceptEither(other, consumer);
CompletionStage acceptEitherAsync(other, consumer);
CompletionStage runAfterEither(other, action);
CompletionStage runAfterEitherAsync(other, action);

CompletionStage<R> thenCombine(other, fn);
CompletionStage<R> thenCombineAsync(other, fn);
CompletionStage<Void> thenAcceptBoth(other, consumer);
CompletionStage<Void> thenAcceptBothAsync(other, consumer);
CompletionStage<Void> runAfterBoth(other, action);
CompletionStage<Void> runAfterBothAsync(other, action);

4.3 or汇聚关系


CompletionStage applyToEither(other, fn);
CompletionStage applyToEitherAsync(other, fn);
CompletionStage acceptEither(other, consumer);
CompletionStage acceptEitherAsync(other, consumer);
CompletionStage runAfterEither(other, action);
CompletionStage runAfterEitherAsync(other, action);

4.4 异常处理


CompletableFuture<Integer> 
  f0 = CompletableFuture.
    .supplyAsync(()->(7/0))
    .thenApply(r->r*10);
System.out.println(f0.join());

正常是try-catch,函数式编程中,更简单,提供了链式处理异常


CompletionStage exceptionally(fn);
CompletionStage<R> whenComplete(consumer);
CompletionStage<R> whenCompleteAsync(consumer);
CompletionStage<R> handle(fn);
CompletionStage<R> handleAsync(fn);

异常范例

CompletableFuture f0 = CompletableFuture .supplyAsync(()->(7/0)) .thenApply(r->r*10) .exceptionally(e->0);System.out.println(f0.join());
原创:做时间的朋友
原文地址:https://www.cnblogs.com/PythonOrg/p/14987204.html