CompletableFuture 詳解(JDK1.8新特性、併發編程)

CompletableFuture 詳解

JDK1.8中的CompletableFuture就爲我們提供了異步函數式編程,CompletableFuture提供了非常強大的Future的擴展功能,可以幫助我們簡化異步編程的複雜性,提供了函數式編程的能力,可以通過回調的方式處理計算結果,並且提供了轉換和組合CompletableFuture的方法。

 

CompletableFuture 提供了四個靜態方法來創建一個異步操作。

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)

 

入參Runnable

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

入參Supplier

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

 

executor參數指定使用的線程池,沒有指定會使用ForkJoinPool.commonPool() 作爲它的線程池執行異步代碼。

runAsync不支持返回值。

supplyAsync支持返回值。

 

示例

CompletableFuture<Void> runAsync = CompletableFuture.runAsync(
        () -> System.out.println("[1]"+Thread.currentThread().getId() + "--" + Thread.currentThread().getName()));


CompletableFuture<String> supplyAsync = CompletableFuture
        .supplyAsync(() -> {
            System.out.println("[2]"+Thread.currentThread().getId() + "--" + Thread.currentThread().getName());
            return "hello";
        });


System.out.println("[3]"+Thread.currentThread().getId() + "--" + Thread.currentThread().getName());

//獲取返回值
System.out.println(runAsync.get());
System.out.println(supplyAsync.get());

結果

[1]50--ForkJoinPool.commonPool-worker-1

[3]30--http-nio-8080-exec-1

[2]50--ForkJoinPool.commonPool-worker-1

null

hello

 

CompletableFuture 回調方法

用於CompletableFuture的計算完成,或者拋出異常的時候,進行下一步操作,主要方法如下:

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)

 

1.exceptionally

當原始的CompletableFuture拋出異常的時候,會進入exceptionally方法,用來處理異常的情況

入參Function

@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

...

}

 

 

2.whenComplete、whenCompleteAsync

whenComplete入參BiConsumer<? super T,? super Throwable>它可以處理正常的計算結果,或者異常情況

第一個參數T:  CompletableFuture計算結果

第二個參數Throwable:CompletableFuture拋出的異常

@FunctionalInterface
public interface BiConsumer<T, U> {

    void accept(T t, U u);

...

}

 

帶async後綴函數,由線程池裏面拿一個空的線程或者新啓一個線程來執行回調,與執行回調的runAsync或suppleAsync線程以及執行whenCompleteAsync事件註冊的線程無關。

 

示例

    CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
        System.out.println("[1]"+Thread.currentThread().getId() + "--" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 1;
    });

    supplyAsync.whenComplete((data, err) -> {
        System.out.println("[2]"+Thread.currentThread().getId() + "--" + Thread.currentThread().getName());
        if (err != null) {
            System.out.println(err.getMessage());
        }
        data++;
        System.out.println("[2]"+data);
    });
    System.out.println("[main]"+supplyAsync.get());
    System.out.println("[main]"+Thread.currentThread().getId() + "--" + Thread.currentThread().getName());
}

結果

[1]51--ForkJoinPool.commonPool-worker-1

[2]51--ForkJoinPool.commonPool-worker-1

[main]1

[main]31--http-nio-8080-exec-1

[2]2

 

runAsync無返回值,whenComplete入參BiConsumer<? super T,? super Throwable>的第一個參數T的類型爲Void

注意

執行whenComplete內容的線程不一定是執行runAsync或suppleAsync的線程,也可能是執行到whenComplete事件註冊的線程。

 

以示例中線程爲例:

當線程【id:51】執行完畢的時候,主線程還沒有執行到whenComplete(即whenComplete事件還沒有註冊),那麼線程【id:51】就不會去同步執行whenComplete的回調。這個時候哪個線程執行到了whenComplete的事件註冊,就由哪個線程自己來同步執行whenComplete的事件內容,示例爲主線程執行。

若線程主線程在線程【id:51】執行完畢前,執行到whenComplete的事件註冊,則由線程【id:51】執行whenComplete內容

 

3.thenApply 

轉化上一個任務的返回結果

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)

入參Function

@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

...

}

與whenComplete的區別

whenComplete返回的CompletableFuture類型與上一個任務類型一致,且whenComplete執行完畢時兩個任務返回值一致。

thenApply返回的CompletableFuture類型、返回值可不與上一個任務類型一致

whenComplete可處理異常情況,而thenApply異常時不執行

 

示例

CompletableFuture<List<String>> supplyAsync1 = CompletableFuture.supplyAsync(() -> Lists.newArrayList("1"));
CompletableFuture<String> stringCompletableFuture = supplyAsync1.thenApply((a) -> a.get(0));
CompletableFuture<List<String>> integerCompletableFuture = supplyAsync1.whenComplete((data, err) -> data.add(1,"2"));
Thread.sleep(1000);
System.out.println("supplyAsync1:"+supplyAsync1.get());
System.out.println("stringCompletableFuture:"+stringCompletableFuture.get());
System.out.println("integerCompletableFuture:"+integerCompletableFuture.get());

結果

supplyAsync1:[1, 2]

stringCompletableFuture:1

integerCompletableFuture:[1, 2]

 

4.thenAccept

接收任務的處理結果,並消費處理,無返回結果。

public CompletionStage<Void> thenAccept(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor);

入參Consumer

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);

...

 

示例

CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> 1);
CompletableFuture<Void> voidCompletableFuture = supplyAsync.thenAccept(data -> System.out.println(data));

 

5.handle

對上一個任務的結果進行處理。
handle 方法和 thenApply 方法處理方式基本一樣。不同的是 handle 是在任務完成後再執行,還可以處理異常的任務。thenApply 只可以執行正常的任務,任務出現異常則不執行 thenApply 方法。

public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Executor executor);

入參BiFunction

@FunctionalInterface
public interface BiFunction<T, U, R> {

    R apply(T t, U u);

...

}

 

handlewhenComplete的區別

1.都是對結果進行處理,handle有返回值,whenComplete沒有返回值

2.上一個任務異常時whenComplete可判斷異常但不處理異常(仍然會拋異常),而handle可實現exceptionally的功能:對異常進行"美化"(不再拋異常)

6、thenRun

跟 thenAccept 方法不一樣的是,不關心任務的處理結果。只要上面的任務執行完成,就開始執行 thenAccept 。

public CompletionStage<Void> thenRun(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);

入參Runnable

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

該方法同 thenAccept 方法類似。不同的是上個任務處理完成後,並不會把計算的結果傳給 thenRun 方法。只是處理完任務後,執行 thenAccept 的後續操作。

7、thenCombine 合併任務

thenCombine 會把兩個 CompletionStage 的任務都執行完成後,把兩個任務的結果一塊交給 thenCombine 來處理(類似thenApply轉化操作)。

public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);


public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);


public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);

入參

參數一:CompletionStage<? extends U> other

Public  class  CompletableFuture<T>  implements Future<T>, CompletionStage<T>

參數二:BiFunction

@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u);

...

 

8、thenAcceptBoth

當兩個CompletionStage都執行完成後,接收兩個任務的處理結果,並消費處理,無返回結果(類似thenAccept)。

public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);


public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);


public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action,     Executor executor);

入參

參數一:CompletionStage<? extends U> other

Public  class  CompletableFuture<T>  implements Future<T>, CompletionStage<T>

參數二:BiConsumer

@FunctionalInterface
public interface BiConsumer<T, U> {

    void accept(T t, U u);

...

}

 

9、applyToEither 方法

兩個CompletionStage,誰執行返回的結果快,就用哪個CompletionStage的結果進行下一步的轉化操作(類似thenApply)。

public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn);


public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn);


public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn,Executor executor);

入參二:Function

@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

...

}

 

10、acceptEither 方法

兩個CompletionStage,誰執行返回的結果快,就用哪個CompletionStage的結果進行下一步的消耗操作(類似thenAccept),無返回值。

public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action);


public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);


public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action,Executor executor);

入參二:Consumer

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);

...

 

11、runAfterEither 方法

兩個CompletionStage,任何一個完成了都會執行下一步的操作(類似thenRun )

public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action);

public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action);


public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);

入參二:Runnable

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

 

12、runAfterBoth

兩個CompletionStage,都完成了計算纔會執行下一步的操作(類似thenRun )

public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action);

public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action);


public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor);

入參二:Runnable

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

 

13、thenCompose 方法

thenCompose 方法允許你對兩個 CompletionStage 進行流水線操作,第一個操作完成時,將其結果作爲參數傳遞給第二個操作。

public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);


public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) ;


public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor) ;

入參Function

@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

...

}

Function<? super T, ? extends CompletionStage<U>> fn

返回值爲CompletionStage類型

 

示例

CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> 1);
CompletableFuture<String> future = supplyAsync
        .thenCompose(integer -> CompletableFuture.supplyAsync(() -> "結果爲:" + integer * 10));

 

 

thenApply()和thenCompose()的區別:

thenapply()是返回的是非CompletableFuture類型:它的功能相當於將CompletableFuture<T>轉換成CompletableFuture<U>。

 

thenCompose()用來連接兩個CompletableFuture,返回值是新的CompletableFuture:

總結:thenApply()轉換的是泛型中的類型,是同一個CompletableFuture;
thenCompose()用來連接兩個CompletableFuture,是生成一個新的CompletableFuture。

 

 

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