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]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章