CompletableFuture的使用

479 阅读2分钟

这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战

CompletableFuture<T>java8中新增的一个类,是对Future<T>接口的一种增强,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果

CompletableFuture<T>类实现了Future<T>, CompletionStage<T>

CompletionStage<T>代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段

1.runAsyncsupplyAsync

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)

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

image.png

image.png

// 不带返回值
CompletableFuture<Void> completable1 = CompletableFuture.runAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("runAsync is end!");
});
// 带返回值
CompletableFuture<Integer> completable2 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("supplyAsync is end!");
    return 10;
});

计算结果完成时回调方法

public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
  • whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务
  • whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。
  • exceptionally:执行失败后调用

案例:

public static void main(String[] args) throws ExecutionException, InterruptedException {

    CompletableFuture<Integer> completable1 = CompletableFuture.supplyAsync(() -> {
        int result = 100 / 2;
        System.out.println("supplyAsync is end!");
        return 10;
    });

    completable1.whenComplete((r, e) -> {
        System.out.println("completable1 is run end");
    });


    CompletableFuture<Integer> completable2 = CompletableFuture.supplyAsync(() -> {
        return 1 / 0;
    });

    CompletableFuture<Integer> completable3 = completable2.exceptionally((e) -> {
        System.out.println("执行任务报错了:" + e.getMessage());
        return 0;
    });

    Integer result = completable3.get();
    System.out.println("result:" + result);
}

输出结果

supplyAsync is end!
completable1 is run end
执行任务报错了:java.lang.ArithmeticException: / by zero
result:0

2.thenApply

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

public static void main(String[] args) throws ExecutionException, InterruptedException {

    ExecutorService executorService = Executors.newFixedThreadPool(10);

    CompletableFuture<Integer> completable1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync is end!");
        return 10;
    }, executorService).thenApply((r) -> {
        return r + 10;
    });

    Integer result = completable1.get();
    System.out.println("result:" + result);

}

输出结果

supplyAsync is end!
result:20

3.handle

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

public static void main(String[] args) throws ExecutionException, InterruptedException {

    ExecutorService executorService = Executors.newFixedThreadPool(10);

    CompletableFuture<Integer> completable1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync is end!");
        int result = 1 / 0;
        return 10;
    }, executorService).handle((p, e) -> {
        if (e != null) {
            System.out.println("supplyAsync run is error " + e.getMessage());
            return -1;
        }
        return p + 10;
    });

    Integer result = completable1.get();
    System.out.println("result:" + result);

    executorService.shutdown();
}

当任务运行出现异常时 打印异常信息 然后返回-1

输出结果

supplyAsync is end!
supplyAsync run is error java.lang.ArithmeticException: / by zero
result:-1

4. thenAccept

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

public static void main(String[] args) throws ExecutionException, InterruptedException {

    ExecutorService executorService = Executors.newFixedThreadPool(10);

    CompletableFuture<Void> completableFuture1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("supplyAsync is end!");
        return 10;
    }, executorService).thenAccept(System.out::println);

    completableFuture1.get();

    executorService.shutdown();
}

当任务运行结束后 调用thenAccept方法消费任务的返回结果

输出结果

supplyAsync is end!
10