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);...
}
handle與whenComplete的區別
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。