這篇文章主要講解了“怎么使用CompletableFuture”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“怎么使用CompletableFuture”吧!
10年積累的成都做網(wǎng)站、成都網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有安寧免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
但Future機(jī)制,還不那么靈活,比如怎么去利用Future機(jī)制描述兩個任務(wù)串行執(zhí)行,又或是兩個任務(wù)并行執(zhí)行,又或是只關(guān)心最先執(zhí)行結(jié)束的任務(wù)結(jié)果。
Future機(jī)制在一定程度上都無法快速地滿足以上需求,CompletableFuture便應(yīng)運(yùn)而生了。
public static CompletableFuture supplyAsync(Supplier supplier) public static CompletableFuture supplyAsync(Supplier supplier,Executor executor); public static CompletableFuturerunAsync(Runnable runnable); public static CompletableFuture runAsync(Runnable runnable,Executor executor);
supplyAsync與runAsync的區(qū)別在于:supplyAsync有返回值,而runAsync沒有返回值
帶Executor參數(shù)的構(gòu)造函數(shù),則使用線程池中的線程執(zhí)行異步任務(wù)(線程池可以參考說說線程池)
不帶Executor參數(shù)的構(gòu)造函數(shù),則使用ForkJoinPool.commonPool()中的線程執(zhí)行異步任務(wù)(Fork/Join框架可以參考談?wù)劜⑿辛鱬arallelStream)
public class Case1 { public static void main(String[] args) throws Exception { CompletableFuturecompletableFuture=CompletableFuture.supplyAsync(()->{ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return 1; }); //該方法會一直阻塞 Integer result = completableFuture.get(); System.out.println(result); } }
public CompletableFuturewhenComplete(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); public CompletableFuture exceptionally(Function fn);
whenComplete開頭的方法在計(jì)算任務(wù)完成(包括正常完成與出現(xiàn)異常)之后會回調(diào)
而exceptionally則只會在計(jì)算任務(wù)出現(xiàn)異常時才會被回調(diào)
如何確定哪個線程去回調(diào)whenComplete,比較復(fù)雜,先略過。
而回調(diào)whenCompleteAsync的線程比較簡單,隨便拿一個空閑的線程即可,后綴是Async的方法同理。
package com.qcy.testCompleteableFuture; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.stream.IntStream; /** * @author qcy * @create 2020/09/07 17:40:44 */ public class Case2 { public static void main(String[] args) throws Exception { CompletableFuturecompletableFuture = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("執(zhí)行supplyAsync的線程:" + Thread.currentThread().getName()); int i = 1 / 0; return 1; }); completableFuture.whenComplete(new BiConsumer () { @Override public void accept(Integer integer, Throwable throwable) { System.out.println("執(zhí)行whenComplete的線程:" + Thread.currentThread().getName()); if (throwable == null) { System.out.println("計(jì)算未出現(xiàn)異常,結(jié)果:" + integer); } } }); completableFuture.exceptionally(new Function () { @Override public Integer apply(Throwable throwable) { //出現(xiàn)異常時,則返回一個默認(rèn)值 System.out.println("計(jì)算出現(xiàn)異常,信息:" + throwable.getMessage()); return -1; } }); System.out.println(completableFuture.get()); } }
輸出:
當(dāng)然,CompletableFuture內(nèi)的各種方法是支持鏈?zhǔn)秸{(diào)用與Lambda表達(dá)式的,我們進(jìn)行如下改寫:
public static void main(String[] args) throws Exception { CompletableFuturecompletableFuture = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("執(zhí)行supplyAsync的線程:" + Thread.currentThread().getName()); int i = 1 / 0; return 1; }).whenComplete((integer, throwable) -> { System.out.println("執(zhí)行whenComplete的線程:" + Thread.currentThread().getName()); if (throwable == null) { System.out.println("計(jì)算未出現(xiàn)異常,結(jié)果:" + integer); } }).exceptionally(throwable -> { //出現(xiàn)異常時,則返回一個默認(rèn)值 System.out.println("計(jì)算出現(xiàn)異常,信息:" + throwable.getMessage()); return -1; }); System.out.println("計(jì)算結(jié)果:" + completableFuture.get()); }
public CompletableFuture thenApply(Function super T,? extends U> fn); public CompletableFuturethenRun(Runnable action); public CompletableFuture thenAccept(Consumer super T> action); public CompletableFuture handle(BiFunction super T, Throwable, ? extends U> fn); public CompletableFuture thenCompose(Function super T, ? extends CompletionStage> fn);
thenApply,依賴上一次任務(wù)執(zhí)行的結(jié)果,參數(shù)中的Function super T,? extends U>,T代表上一次任務(wù)返回值的類型,U代表當(dāng)前任務(wù)返回值的類型,當(dāng)上一個任務(wù)沒有出現(xiàn)異常時,thenApply才會被調(diào)用
thenRun,不需要知道上一個任務(wù)的返回結(jié)果,只是在上一個任務(wù)執(zhí)行完成之后開始執(zhí)行Runnable
thenAccept,依賴上一次任務(wù)的執(zhí)行結(jié)果,因?yàn)槿雲(yún)⑹荂onsumer,所以不返回任何值。
handle和thenApply相似,不過當(dāng)上一個任務(wù)出現(xiàn)異常時,能夠執(zhí)行handle,卻不會去執(zhí)行thenApply
thenCompose,傳入一次任務(wù)執(zhí)行的結(jié)果,返回一個新的CompleteableFuture對象
package com.qcy.testCompleteableFuture; import java.util.concurrent.CompletableFuture; /** * @author qcy * @create 2020/09/07 17:40:44 */ public class Case4 { public static void main(String[] args) { CompletableFuture.supplyAsync(() -> 2) .thenApply(num -> num * 3) .thenAccept(System.out::print); } }
很顯然,輸出為6
package com.qcy.testCompleteableFuture; import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; /** * @author qcy * @create 2020/09/07 17:40:44 */ public class Case4 { public static void main(String[] args) { CompletableFuture.supplyAsync(() -> 2) .thenApply(num -> num / 0) .thenApply(result -> result * 3) .handle((integer, throwable) -> { if (throwable == null) { return integer; } else { throwable.printStackTrace(); return -1; } }).thenAccept(System.out::print); } }
最終會輸出-1
public CompletableFuturethenCombine(CompletionStage extends U> other, Function super T,? super U,? extends V> fn); public CompletableFuture thenAcceptBoth(CompletionStage extends U> other, Consumer super T, ? super U> action); public CompletableFuture runAfterBoth(CompletionStage> other,Runnable action); public static CompletableFuture allOf(CompletableFuture>... cfs);
thenCombine,合并兩個任務(wù),兩個任務(wù)可以同時執(zhí)行,都執(zhí)行成功后,執(zhí)行最后的BiFunction操作。其中T代表第一個任務(wù)的執(zhí)行結(jié)果類型,U代表第二個任務(wù)的執(zhí)行結(jié)果類型,V代表合并的結(jié)果類型
thenAcceptBoth,和thenCombine特性用法都極其相似,唯一的區(qū)別在于thenAcceptBoth進(jìn)行一個消費(fèi),沒有返回值
runAfterBoth,兩個任務(wù)都執(zhí)行完成后,但不關(guān)心他們的返回結(jié)構(gòu),然后去執(zhí)行一個Runnable。
allOf,當(dāng)所有的任務(wù)都執(zhí)行完成后,返回一個CompletableFuture
package com.qcy.testCompleteableFuture; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; /** * @author qcy * @create 2020/09/07 17:40:44 */ public class Case5 { public static void main(String[] args) throws Exception { CompletableFuturecf1 = CompletableFuture.supplyAsync(() -> { System.out.println("任務(wù)1開始"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任務(wù)1結(jié)束"); return 2; }); CompletableFuture cf2 = CompletableFuture.supplyAsync(() -> { System.out.println("任務(wù)2開始"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任務(wù)2結(jié)束"); return 3; }); CompletableFuture completableFuture = cf1.thenCombine(cf2, (result1, result2) -> result1 * result2); System.out.println("計(jì)算結(jié)果:" + completableFuture.get()); } }
輸出:
可以看到兩個任務(wù)確實(shí)是同時執(zhí)行的
當(dāng)然,熟練了之后,直接使用鏈?zhǔn)讲僮?,代碼如下:
package com.qcy.testCompleteableFuture; import java.util.concurrent.CompletableFuture; /** * @author qcy * @create 2020/09/07 17:40:44 */ public class Case6 { public static void main(String[] args) throws Exception { CompletableFuturecompletableFuture = CompletableFuture.supplyAsync(() -> { System.out.println("任務(wù)1開始"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任務(wù)1結(jié)束"); return 2; }).thenCombine(CompletableFuture.supplyAsync(() -> { System.out.println("任務(wù)2開始"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任務(wù)2結(jié)束"); return 3; }), (result1, result2) -> result1 * result2); System.out.println("計(jì)算結(jié)果:" + completableFuture.get()); } }
public CompletableFuture applyToEither(CompletionStage extends T> other, Function super T, U> fn); public CompletableFutureacceptEither(CompletionStage extends T> other, Consumer super T> action); public CompletableFuture runAfterEither(CompletionStage> other,Runnable action); public static CompletableFuture
applyToEither,最新執(zhí)行完任務(wù),將其結(jié)果執(zhí)行Function操作,其中T是最先執(zhí)行完的任務(wù)結(jié)果類型,U是最后輸出的類型
acceptEither,最新執(zhí)行完的任務(wù),將其結(jié)果執(zhí)行消費(fèi)操作
runAfterEither,任意一個任務(wù)執(zhí)行完成之后,執(zhí)行Runnable操作
anyOf,多個任務(wù)中,返回最先執(zhí)行完成的CompletableFuture
package com.qcy.testCompleteableFuture; import java.util.concurrent.CompletableFuture; /** * @author qcy * @create 2020/09/07 17:40:44 */ public class Case7 { public static void main(String[] args) throws Exception { CompletableFuturecompletableFuture = CompletableFuture.supplyAsync(() -> { System.out.println("任務(wù)1開始"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任務(wù)1結(jié)束"); return 2; }).acceptEither(CompletableFuture.supplyAsync(() -> { System.out.println("任務(wù)2開始"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任務(wù)2結(jié)束"); return 3; }), result -> System.out.println(result)); //等待CompletableFuture返回,防止主線程退出 completableFuture.join(); } }
輸出:
可以看得到,任務(wù)2結(jié)束后,直接不再執(zhí)行任務(wù)1的剩余代碼
package com.qcy.testCompleteableFuture; import java.util.concurrent.CompletableFuture; /** * @author qcy * @create 2020/09/07 17:40:44 */ public class Case8 { public static void main(String[] args) throws Exception { CompletableFuturecf1 = CompletableFuture.supplyAsync(() -> { System.out.println("任務(wù)1開始"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任務(wù)1結(jié)束"); return 2; }); CompletableFuture cf2 = CompletableFuture.supplyAsync(() -> { System.out.println("任務(wù)2開始"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任務(wù)2結(jié)束"); return 3; }); CompletableFuture cf3 = CompletableFuture.supplyAsync(() -> { System.out.println("任務(wù)3開始"); try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("任務(wù)3結(jié)束"); return 4; }); CompletableFuture
輸出:
感謝各位的閱讀,以上就是“怎么使用CompletableFuture”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對怎么使用CompletableFuture這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!