Java——CompletableFuture接口解析

CompletableFuture接口说明

CompletableFuture是Future的子类,接口Future接口虽然实现了异步调用,但是存在一个问题,为了判断线程是否已完成计算,或者要获取计算结果,我们需要不断的轮询,通过循环调用Future的isDone方法或者是直接调用get的方法阻塞线程。

在JDK8中,提供了CompletableFuture类来解决这类问题,它可以在线程完成计算后用when、then等方式调用我们定义后续处理方法,省去了轮询的操作(笔者最近在读RocketMQ源码,发现在Broker上使用了CompletableFuture类,因此打算记录一下基本功能和用法,希望后续有时间能详细研读一下实现源码。)

CompletableFuture有以下几种构造方式:

//没有计算过程,直接返回计算结果
CompletableFuture<String>futureNoComplete=CompletableFuture.completedFuture("hello world");

//没有返回值的异步计算
CompletableFuture<Void>futureNoReturnNoExecutor=CompletableFuture.runAsync(()->doSomething());
CompletableFuture<Void>futureNoReturnWithExecutor=CompletableFuture.runAsync(()->doSomething(), Executors.newSingleThreadExecutor());

//带返回值的异步计算
CompletableFuture<String> futureWithReturnNoExector=CompletableFuture.supplyAsync(()->doSomethingReturnString());
CompletableFuture<String> futureWithReturnWithExecutor=CompletableFuture.supplyAsync(()->doSomethingReturnString(), Executors.newSingleThreadExecutor());

当completeFuture代表的任务完成了,可以使用一系列的函数接口来定义当前Future完成后的后续计算。

//执行完当前任务后,以当前任务的返回值作为fn任务的输入,并返回计算结果
 	public <U> CompletableFuture<U> thenApply(
        Function<? super T,? extends U> fn) {
        return uniApplyStage(null, fn);
    }
//执行完当前任务后,将返回值作为输入,计算fn任务,并返回结果
 	public <U> CompletableFuture<U> thenApplyAsync(
        Function<? super T,? extends U> fn) {
        return uniApplyStage(asyncPool, fn);
    }

//执行完当前任务后,以当前任务返回值作为输入,并返回计算结果,该计算过程使用executor中的不同线程来执行
 	public <U> CompletableFuture<U> thenApplyAsync(
        Function<? super T,? extends U> fn, Executor executor) {
        return uniApplyStage(screenExecutor(executor), fn);
    }

//执行完当前任务后,将返回值作为action任务的输入参数进行计算
    public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
        return uniAcceptStage(null, action);
    }

//执行完当前任务后,将返回值作为action任务的输入参数进行计算
    public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
        return uniAcceptStage(asyncPool, action);
    }
//执行完当前任务后,将返回值作为action任务的输入参数进行计算
    public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
                                                   Executor executor) {
        return uniAcceptStage(screenExecutor(executor), action);
    }
//执行完当前任务后,执行action定义的任务
    public CompletableFuture<Void> thenRun(Runnable action) {
        return uniRunStage(null, action);
    }
//执行完当前任务后,执行action任务
    public CompletableFuture<Void> thenRunAsync(Runnable action) {
        return uniRunStage(asyncPool, action);
    }
//执行完当前任务后,执行action任务,action任务使用executor的线程执行
    public CompletableFuture<Void> thenRunAsync(Runnable action,
                                                Executor executor) {
        return uniRunStage(screenExecutor(executor), action);
    }
	//执行完当前任务,和另一个CompletableFuture的任务other,将两个任务的返回值作为参数执行fn,返回该计算过程的CompletableFuture
    public <U,V> CompletableFuture<V> thenCombine(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn) {
        return biApplyStage(null, other, fn);
    }
	//执行完当前任务,和另一个CompletableFuture的任务other,将两个任务的返回值作为参数执行fn,返回该计算过程的CompletableFuture
    public <U,V> CompletableFuture<V> thenCombineAsync(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn) {
        return biApplyStage(asyncPool, other, fn);
    }
//执行完当前任务,和另一个CompletableFuture的任务other,将两个任务的返回值作为参数执行fn,返回该计算过程的CompletableFuture,计算过程中会使用executor的线程计算
    public <U,V> CompletableFuture<V> thenCombineAsync(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
        return biApplyStage(screenExecutor(executor), other, fn);
    }
//执行完当前任务,和另一个CompletableFuture的任务other,将两个任务的返回值作为参数执行fn
    public <U> CompletableFuture<Void> thenAcceptBoth(
        CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action) {
        return biAcceptStage(null, other, action);
    }
//执行完当前任务,和另一个CompletableFuture的任务other,将两个任务的返回值作为参数执行fn
    public <U> CompletableFuture<Void> thenAcceptBothAsync(
        CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action) {
        return biAcceptStage(asyncPool, other, action);
    }
//执行完当前任务,和另一个CompletableFuture的任务other,将两个任务的返回值作为参数执行fn,计算过程使用executor的线程执行
    public <U> CompletableFuture<Void> thenAcceptBothAsync(
        CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action, Executor executor) {
        return biAcceptStage(screenExecutor(executor), other, action);
    }
//在当前任务和另一个CompletableFuture的任务执行完毕后,执行action
    public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
                                                Runnable action) {
        return biRunStage(null, other, action);
    }
//在当前任务和另一个CompletableFuture的任务执行完毕后,执行action
    public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
                                                     Runnable action) {
        return biRunStage(asyncPool, other, action);
    }
//在当前任务和另一个CompletableFuture的任务执行完毕后,执行action,计算过程会使用executor的线程执行
    public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
                                                     Runnable action,
                                                     Executor executor) {
        return biRunStage(screenExecutor(executor), other, action);
    }
//计算当前任务与other的任务,计算快的返回结果作为fn的输入进行计算,并返回计算结果的CompleteFuture
    public <U> CompletableFuture<U> applyToEither(
        CompletionStage<? extends T> other, Function<? super T, U> fn) {
        return orApplyStage(null, other, fn);
    }
//计算当前任务与other的任务,计算快的返回结果作为fn的数据进行计算,并返回计算结果的CompleteFuture
    public <U> CompletableFuture<U> applyToEitherAsync(
        CompletionStage<? extends T> other, Function<? super T, U> fn) {
        return orApplyStage(asyncPool, other, fn);
    }
//计算当前任务与other的任务,计算快的返回结果作为fn的输入进行计算,并返回计算结果的CompleteFuture,计算过程会使用executor的线程执行
    public <U> CompletableFuture<U> applyToEitherAsync(
        CompletionStage<? extends T> other, Function<? super T, U> fn,
        Executor executor) {
        return orApplyStage(screenExecutor(executor), other, fn);
    }
//计算当前任务与other的任务,计算快的返回结果作为action的输入进行计算
    public CompletableFuture<Void> acceptEither(
        CompletionStage<? extends T> other, Consumer<? super T> action) {
        return orAcceptStage(null, other, action);
    }
//计算当前任务与other的任务,计算快的返回结果作为action的输入进行计算
    public CompletableFuture<Void> acceptEitherAsync(
        CompletionStage<? extends T> other, Consumer<? super T> action) {
        return orAcceptStage(asyncPool, other, action);
    }
//计算当前任务与other的任务,计算快的返回结果作为action的输入进行计算,计算过程使用executor的线程执行
    public CompletableFuture<Void> acceptEitherAsync(
        CompletionStage<? extends T> other, Consumer<? super T> action,
        Executor executor) {
        return orAcceptStage(screenExecutor(executor), other, action);
    }
//当前任务和other的任务,只要有一个任务完成,就执行action
    public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
                                                  Runnable action) {
        return orRunStage(null, other, action);
    }
//当前任务和other的任务,只要有一个任务完成,就执行action
    public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
                                                       Runnable action) {
        return orRunStage(asyncPool, other, action);
    }
//当前任务和other的任务,只要有一个任务完成,就执行action,所有计算过程使用executor的线程
    public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
                                                       Runnable action,
                                                       Executor executor) {
        return orRunStage(screenExecutor(executor), other, action);
    }

//在当前的任务完成后,生成一个新的CompletableFuture
    public <U> CompletableFuture<U> thenCompose(
        Function<? super T, ? extends CompletionStage<U>> fn) {
        return uniComposeStage(null, fn);
    }
//在当前的任务完成后,生成一个新的CompletableFuture,与thenApply需要注意区别
    public <U> CompletableFuture<U> thenComposeAsync(
        Function<? super T, ? extends CompletionStage<U>> fn) {
        return uniComposeStage(asyncPool, fn);
    }
//在当前的任务完成后,生成一个新的CompletableFuture,计算过程使用executor的线程
    public <U> CompletableFuture<U> thenComposeAsync(
        Function<? super T, ? extends CompletionStage<U>> fn,
        Executor executor) {
        return uniComposeStage(screenExecutor(executor), fn);
    }
//在当前任务完成后,执行action。该方法不会使用ForkJoinPool的线程,需要与thenapply区分
    public CompletableFuture<T> whenComplete(
        BiConsumer<? super T, ? super Throwable> action) {
        return uniWhenCompleteStage(null, action);
    }
//在当前任务完成后,执行action
    public CompletableFuture<T> whenCompleteAsync(
        BiConsumer<? super T, ? super Throwable> action) {
        return uniWhenCompleteStage(asyncPool, action);
    }
//在当前任务完成后,执行action,action是使用executor线程池执行
    public CompletableFuture<T> whenCompleteAsync(
        BiConsumer<? super T, ? super Throwable> action, Executor executor) {
        return uniWhenCompleteStage(screenExecutor(executor), action);
    }

CompleteFuture不带Async和带Async方法的区别:

  • 带Async的方法比较简单,就是每个计算过程都会使用线程池中的线程来执行,如果没有指定使用的线程池,那么会使用默认的ForkJoinPool,如果指定了Executor,那么直接使用指定的线程池即可。
  • 不带Async的方法执行较为复杂,要分成两种情况。
    以thenAccept方法为例:

第一种情况,在任务A还没执行完的时候,主线程就通过thenAccept方法设置了任务A执行完后要执行任务B,代码和对应的输出结果如下:

 CompletableFuture<String> completableFuture=CompletableFuture.supplyAsync(()->{
            //分配了ForkJoinPool的线程执行
            System.out.println("task A: "+Thread.currentThread());
            try {
                Thread.sleep(2000);
            }catch (Exception e){
                e.printStackTrace();
            }
            return "task A";
        });

        System.out.println(Thread.currentThread());
        //Thread.sleep(5000);
        completableFuture.thenAccept(str->{
            System.out.println("task B: "+Thread.currentThread());
        });

输出结果:

Thread[main,5,main]
task A: Thread[ForkJoinPool.commonPool-worker-11,5,main]
task B: Thread[ForkJoinPool.commonPool-worker-11,5,main]

第二种情况,设置的任务A已经被子线程执行完毕,但是主线程还没通过thenAccept方法去设置后续任务B的操作,那么这个时候,只能由主线程执行任务B的操作,代码和输出如下:

CompletableFuture<String> completableFuture=CompletableFuture.supplyAsync(()->{
            //分配了ForkJoinPool的线程执行
            System.out.println("task A: "+Thread.currentThread());
            try {
                Thread.sleep(2000);
            }catch (Exception e){
                e.printStackTrace();
            }
            return "task A";
        });

        System.out.println(Thread.currentThread());
        //等待子线程将任务A计算完成,再去设置任务B
        Thread.sleep(5000);
        completableFuture.thenAccept(str->{
            System.out.println("task B: "+Thread.currentThread());
        });
    }

输出结果:

Thread[main,5,main]
task A: Thread[ForkJoinPool.commonPool-worker-11,5,main]
task B: Thread[main,5,main]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章