CompletableFuture

https://www.jianshu.com/p/6bac52527ca4

1、 runAsync 和 supplyAsync方法

CompletableFuture 提供了四个静态方法来创建一个异步操作。

public static CompletableFuture runAsync(Runnable runnable)
public static CompletableFuture runAsync(Runnable runnable, Executor executor)
public static  CompletableFuture supplyAsync(Supplier supplier)
public static  CompletableFuture supplyAsync(Supplier supplier, Executor executor)

没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。

  • runAsync方法不支持返回值。
  • supplyAsync可以支持返回值。

示例

//无返回值
public static void runAsync() throws Exception {
    CompletableFuture future = CompletableFuture.runAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
        }
        System.out.println("run end ...");
    });
    
    future.get();
}

//有返回值
public static void supplyAsync() throws Exception {         
    CompletableFuture future = CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
        }
        System.out.println("run end ...");
        return System.currentTimeMillis();
    });

    long time = future.get();
    System.out.println("time = "+time);
}

2、计算结果完成时的回调方法

当CompletableFuture的计算结果完成,或者抛出异常的时候,可以执行特定的Action。主要是下面的方法:

public CompletableFuture whenComplete(BiConsumer action)
public CompletableFuture whenCompleteAsync(BiConsumer action)
public CompletableFuture whenCompleteAsync(BiConsumer action, Executor executor)
public CompletableFuture exceptionally(Function fn)

可以看到Action的类型是BiConsumer它可以处理正常的计算结果,或者异常情况。

whenComplete 和 whenCompleteAsync 的区别:
whenComplete:是执行当前任务的线程执行结束后继续执行 whenComplete 的任务。
whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。

示例

public static void whenComplete() throws Exception {
    CompletableFuture future = CompletableFuture.runAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
        }
        if(new Random().nextInt()%2>=0) {
            int i = 12/0;
        }
        System.out.println("run end ...");
    });
    
    future.whenComplete(new BiConsumer() {
        @Override
        public void accept(Void t, Throwable action) {
            System.out.println("执行完成!");
        }
        
    });
    future.exceptionally(new Function() {
        @Override
        public Void apply(Throwable t) {
            System.out.println("执行失败!"+t.getMessage());
            return null;
        }
    });
    
    TimeUnit.SECONDS.sleep(2);
}

3、thenApply 方法

当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化。

public  CompletableFuture thenApply(Function fn)
public  CompletableFuture thenApplyAsync(Function fn)
public  CompletableFuture thenApplyAsync(Function fn, Executor executor)

Function
T:上一个任务返回结果的类型
U:当前任务的返回值类型

public void thenApply() throws Exception {
    //第二个任务依赖第一个任务的结果
    CompletableFuture future = CompletableFuture.supplyAsync(() -> 5).thenApply((m -> m + 2));

    Integer rs = future.get();

    System.out.println(rs);
  }

4、handle 方法

handle 是执行任务完成时对结果的处理。
handle 方法和 thenApply 方法处理方式基本一样。不同的是 handle 是在任务完成后再执行,还可以处理异常的任务。thenApply 只可以执行正常的任务,任务出现异常则不执行 thenApply 方法。

public  CompletionStage handle(BiFunction fn);
public  CompletionStage handleAsync(BiFunction fn);
public  CompletionStage handleAsync(BiFunction fn,Executor executor);

从示例中可以看出,在 handle 中可以根据任务是否有异常来进行做相应的后续处理操作。而 thenApply 方法,如果上个任务出现错误,则不会执行 thenApply 方法。

public void handle() throws Exception {
    //从示例中可以看出,在 handle 中可以根据任务是否有异常来进行做相应的后续处理操作。
    //而 thenApply 方法,如果上个任务出现错误,则不会执行 thenApply 方法。
    CompletableFuture future = CompletableFuture.supplyAsync(() -> 2/0)
      .handle((m, throwable) -> {
      int result = -1;
      if (Objects.isNull(throwable)) {
        result = m + 5;
      } else {
        System.out.println(throwable.getMessage());
      }
      return result;
    });
    System.out.println(future.get());
  }

5、接收任务的处理结果,并消费处理,无返回结果

/**
   * 接收任务的处理结果,并消费处理,无返回结果
   * public CompletionStage thenAccept(Consumer action);
   * public CompletionStage thenAcceptAsync(Consumer action);
   * public CompletionStage thenAcceptAsync(Consumer action,Executor executor);
   */
  @Test
  public void thenAccept() throws Exception {

    CompletableFuture future = CompletableFuture.supplyAsync(() -> 5).thenAccept(val -> {
      System.out.println(val + 10);
    });

    //thenAccept结果消费了, 此处无返回结果
    System.out.println(future.get()); //null
  }

6、thenRun 方法

跟 thenAccept 方法不一样的是,不关心任务的处理结果。只要上面的任务执行完成,就开始执行 thenRun

public void thenRun() throws Exception {

    CompletableFuture future = CompletableFuture.supplyAsync(() -> 5).thenRun(() -> {
      System.out.println("thenRun");
    });
 
    System.out.println(future.get()); //null
  }

7、thenCombine 方法

thenCombine 会把 两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理

public void thenCombine() throws Exception {
    CompletableFuture f1 = CompletableFuture.supplyAsync(() -> 3);
    CompletableFuture f2 = CompletableFuture.supplyAsync(() -> 5);

    CompletableFuture combine = f1.thenCombine(f2, Integer::sum);
    System.out.println(combine.get()); //8
  }

8、thenAcceptBoth 方法

当两个CompletionStage都执行完成后,把结果一块交给thenAcceptBoth来进行消耗

public void thenAcceptBoth() {
    CompletableFuture f1 = CompletableFuture.supplyAsync(() -> 3);
    CompletableFuture f2 = CompletableFuture.supplyAsync(() -> 5);

    f1.thenAcceptBoth(f2, (a, b) -> {
      System.out.println(a * b); //15
    });
  }

你可能感兴趣的:(CompletableFuture)