CompletableFuture API用法介绍(一)

一、前言

CompletableFuture类实现了CompletionStage和Future接口。Future是Java 5添加的类,用来描述一个异步计算的结果,但是获取一个结果时方法较少,要么通过轮询isDone,确认完成后,调用get()获取值,要么调用get()设置一个超时时间。但是这个get()方法会阻塞着调用线程,这种阻塞的方式显然和我们的异步编程的初衷相违背。
为了解决这个问题,JDK吸收了guava的设计思想,加入了Future的诸多扩展功能形成了CompletableFuture。

敲黑板:以Async结尾的方法都是可以异步执行的,如果指定了线程池,会在指定的线程池中执行,如果没有指定,默认会在ForkJoinPool.commonPool()中执行

二、CompletableFuture

CompletableFuture 是Java 8 新增加的Api,该类实现,Future和CompletionStage两个接口,提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合CompletableFuture的方法

1、主动完成计算

  • public T get()
    该方法时阻塞方法,会等待计算结果完成
  • public T get(long timeout, TimeUnit unit)
    有时间限制的阻塞方法
  • public T getNow(T valueIfAbsent)
    立即获取方法结果,如果没有计算结束则返回传的值
  • public T join()
    和 get() 方法类似也是主动阻塞线程,等待计算结果。和get() 方法有细微的差别

举例如下:

public static void completableFutureGet() throws  Exception{
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 100 * 10;
        });
        System.out.println(completableFuture.get());
        System.out.println(completableFuture.get(1000, TimeUnit.MICROSECONDS));
        System.out.println(completableFuture.join());
        System.out.println(completableFuture.getNow(1));
    }
  • public boolean complete(T value)

立即完成计算,并把结果设置为传的值,返回是否设置成功

如果 CompletableFuture 没有关联任何的Callback、异步任务等,如果调用get方法,那会一直阻塞下去,可以使用complete方法主动完成计算。

2、创建异步任务

  • public static CompletableFuture completedFuture(U value)
    创建一个有初始值的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)

以上四个方法中,以 Async 结尾并且没有 Executor 参数的,会默认使用 ForkJoinPool.commonPool() 作为它的线程池执行异步代码。 以run开头的,因为以 Runable 类型为参数所以没有返回值。示例:

 public static void completableFutureSupplyAsync()throws Exception {
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> System.out.println("runAsync"));
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "supplyAsync");

        System.out.println(future1.get());
        System.out.println(future2.get());
    }

3、计算完成时对结果的处理 whenComplete/exceptionally/handle

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

  • public CompletableFuture whenComplete(BiConsumer<? super T,? super Throwable> action)
  • public CompletableFuture whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
  • public CompletableFuture whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
    参数类型为 BiConsumer<? super T, ? super Throwable> 会获取上一步计算的计算结果和异常信息。以Async结尾的方法可能会使用其它的线程去执行,如果使用相同的线程池,也可能会被同一个线程选中执行,以下皆相同。
public static void completableFutureWhenComplete()throws Exception {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 20;
        }).whenCompleteAsync((v, e) -> {
            System.out.println(v);
            System.out.println(e);
        });
        System.out.println(future.get());
    }
  • public CompletableFuture exceptionally(Function<Throwable,? extends T> fn)
    该方法是对异常情况的处理,当函数异常时应该的返回值
public static void completableFutureExceptionally()throws Exception {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10 / 0;
        }).whenCompleteAsync((v, e) -> {
            System.out.println(v);
            System.out.println(e);
        }).exceptionally((e) -> {
            System.out.println(e.getMessage());
            return 30;
        });
        System.out.println(future.get());
    }
  • public CompletableFuture handle(BiFunction<? super T,Throwable,? extends U> fn)
  • public CompletableFuture handleAsync(BiFunction<? super T,Throwable,? extends U> fn)
  • public CompletableFuture handleAsync(BiFunction<? super T,Throwable,? extends U> fn, Executor executor)
    handle 方法和whenComplete方法类似,只不过接收的是一个 BiFunction<? super T,Throwable,? extends U> fn 类型的参数,因此有 whenComplete 方法和 转换的功能 (thenApply)
 public static void completableFutureHand()throws Exception {

        CompletableFuture<Integer> future = CompletableFuture
                .supplyAsync(() -> 10 / 0)
                .handle((t, e) -> {
                    System.out.println(e.getMessage());
                    return 10;
                });

        System.out.println(future.get());
    }
}

4、结果转换

CompletableFuture 由于有回调,可以不必等待一个计算完成而阻塞着调用线程,可以在一个结果计算完成之后紧接着执行某个Action。我们可以将这些操作串联起来。

  • public CompletableFuture thenApply(Function<? super T,? extends U> fn)
  • public CompletableFuture thenApplyAsync(Function<? super T,? extends U> fn)
  • public CompletableFuture thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
 public static void completableFutureThenApply()throws Exception {
        CompletableFuture<Integer> future = CompletableFuture
                .supplyAsync(() -> 1)
                .thenApply((a) -> {
                    System.out.println(a);//1
                    return a * 10;
                }).thenApply((a) -> {
                    System.out.println(a);//10
                    return a + 10;
                }).thenApply((a) -> {
                    System.out.println(a);//20
                    return a - 5;
                });
        System.out.println(future.get());//15
    }
}

这些方法不是马上执行的,也不会阻塞,而是前一个执行完成后继续执行下一个。

和 handle 方法的区别是,handle 会处理正常计算值和异常,不会抛出异常。而 thenApply 只会处理正常计算值,有异常则抛出。

从上面API可以看出,我们的并发编程在jdk1.8变的更加简单了。以上是部分CompletableFuture API用法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

境里婆娑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值