Java多線程開(kāi)發(fā)工具之CompletableFuture的應(yīng)用詳解
做Java編程,難免會(huì)遇到多線程的開(kāi)發(fā),但是JDK8這個(gè)CompletableFuture類(lèi)很多開(kāi)發(fā)者目前還沒(méi)聽(tīng)說(shuō)過(guò),但是這個(gè)類(lèi)實(shí)在是太好用了,了解它的一些用法后相信你會(huì)對(duì)它愛(ài)不釋手(呸渣男,咋對(duì)誰(shuí)都愛(ài)不釋手呢),好了我先簡(jiǎn)單舉個(gè)列子,告訴你用它有多好。Single Dog拿一個(gè)Appointment來(lái)舉個(gè)列子,如下:
/** * 女神化完妝之后,還需要一小會(huì)選衣服,不過(guò)分吧。 * 也就是說(shuō)我們現(xiàn)在有2個(gè)異步任務(wù),第一個(gè)是化妝,第二個(gè)是選衣服。 * 選衣服要在化妝完成之后進(jìn)行,這兩個(gè)任務(wù)是串行 */ public static void main(String[] args) { // 線程池我前面的文章聊過(guò),怎么配置可以去了解一下 ThreadPoolExecutor threadPool= new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); //任務(wù)1 CompletableFuture<String> makeUpFuture = CompletableFuture.supplyAsync(() -> { System.out.println(Thread.currentThread().getName() + "-女神,開(kāi)始化妝了"); try { // 化妝的時(shí)間 TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } return "化妝完畢了。"; }, threadPool); //任務(wù)2,makeUp是調(diào)用方,意思是makeUpFuture執(zhí)行完后再執(zhí)行 CompletableFuture<String> dressFuture = makeUpFuture.thenApply((result) -> { System.out.println(Thread.currentThread().getName() + "-女神" + result + "我開(kāi)始選衣服啦,好了叫你!"); try { // 換衣服的時(shí)間 TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } return result + "衣服也選好了,走出去玩吧!"; }); dressFuture.thenAccept((result) -> { System.out.println(Thread.currentThread().getName() + "-" + result); }); }
上面的2個(gè)任務(wù)也可以理解為我們開(kāi)發(fā)中要實(shí)現(xiàn)的不同功能,看明白前面的列子了吧?用它來(lái)寫(xiě)多線程運(yùn)用的多絲滑。那我們就先講一下它的核心的靜態(tài)的方法,推薦用它的靜態(tài)方法不要直接new對(duì)象。
1:無(wú)返回值的靜態(tài)方法:
?public static CompletableFuture<Void> runAsync(Runnable runnable)。
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) 。
上面一個(gè)2個(gè)方法,如果沒(méi)有指定Executor就使用默認(rèn)的ForkJoinPool.commonPool()線程池,如果指定線程池就使用指定的。
2:有返回值的方法
?public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
如果開(kāi)始的代碼你還看不懂那介紹了上面的幾個(gè)方法就先小試牛刀一下:
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); ? CompletableFuture.runAsync(() -> { System.out.println(Thread.currentThread().getName()); int i = 10 / 2; System.out.println("運(yùn)行的結(jié)果是:" + i); }, threadPool); ? CompletableFuture future = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return "Hello World"; }, threadPool); System.out.println(future.get());
好了講過(guò)它的使用方法了那我們就聊一下它的幾個(gè)使用的場(chǎng)景,開(kāi)發(fā)中這寫(xiě)場(chǎng)景應(yīng)該會(huì)使用到。
?1:執(zhí)行任務(wù) A,執(zhí)行任務(wù)B,待任務(wù)B執(zhí)行完成后,用B的返回值區(qū)執(zhí)行任務(wù)C。
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("執(zhí)行任務(wù)A"); return "任務(wù)A"; }, executor); CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> { System.out.println("執(zhí)行任務(wù)B"); return "任務(wù)B"; }, executor); CompletableFuture<String> futurec = futureB.thenApply((b) -> { System.out.println("執(zhí)行任務(wù)C"); System.out.println("參數(shù):" + b); return "a"; }); System.out.println(futurec.get());
?運(yùn)行結(jié)果,注意我上面沒(méi)說(shuō)B一定要在A執(zhí)行以后執(zhí)行。
場(chǎng)景2:多個(gè)任務(wù)串聯(lián)執(zhí)行,下一個(gè)任務(wù)的執(zhí)行依賴上一個(gè)任務(wù)的結(jié)果,每個(gè)任務(wù)都有輸入和輸出。
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); CompletableFuture futureA = CompletableFuture.supplyAsync(() -> "Hello", executor); CompletableFuture futureB = futureA.thenApply((a) -> a + " World"); CompletableFuture futureC = futureB.thenApply((b) -> b); System.out.println(futureC.join());
?輸出結(jié)果,開(kāi)發(fā)中的經(jīng)典場(chǎng)景輸出:
?場(chǎng)景3:thenCombineAsync 聯(lián)合 futureA和futureB的返回結(jié)果,然后在返回相關(guān)的數(shù)據(jù)
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); CompletableFuture<Integer> futureA = CompletableFuture.supplyAsync(() -> 10, executor); CompletableFuture<Integer> futureB = CompletableFuture.supplyAsync(() -> 20, executor); CompletableFuture futureC = futureA.thenCombineAsync(futureB, (r1, r2) -> { System.out.println("r1的值為:" + r1 + ":r2的值為:" + r2); return r1 + r2; }); System.out.println(futureC.get());
?結(jié)果輸出:
好了聊完幾個(gè)場(chǎng)景那就寫(xiě)一個(gè)在開(kāi)發(fā)中的經(jīng)典運(yùn)用。
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); System.out.println("start..."); CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> { System.out.println("查詢商品信息1"); return "future1"; }, executor); ? CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> { System.out.println("查詢商品信息2"); return "future2"; }, executor); ? CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> { System.out.println("查詢商品信息3"); return "future3"; }, executor); ? final CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(future1, future2, future3); voidCompletableFuture.get(); System.out.println("end...future1的結(jié)果:" + future1.get() + ",future2的結(jié)果:" + future2.get() + ",future3的結(jié)果:" + future3.get());
?輸出結(jié)果
?這個(gè)經(jīng)典的應(yīng)用相信你可以在你的開(kāi)發(fā)中進(jìn)行套用,然后靈活的運(yùn)用。當(dāng)然這個(gè)類(lèi)還有很多的方法,我這里只寫(xiě)了部分介紹了部分場(chǎng)景作為一個(gè)引子,如果想了解它的更多的應(yīng)用可以看它的API的文檔。
到此這篇關(guān)于Java多線程開(kāi)發(fā)工具之CompletableFuture的應(yīng)用詳解的文章就介紹到這了,更多相關(guān)Java CompletableFuture內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Spring?Boot+gRPC構(gòu)建微服務(wù)并部署的案例詳解
這篇文章主要介紹了使用Spring?Boot+gRPC構(gòu)建微服務(wù)并部署,Spring Cloud僅僅是一個(gè)開(kāi)發(fā)框架,沒(méi)有實(shí)現(xiàn)微服務(wù)所必須的服務(wù)調(diào)度、資源分配等功能,這些需求要借助Kubernetes等平臺(tái)來(lái)完成,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-06-06關(guān)于Java中try finally return語(yǔ)句的執(zhí)行順序淺析
這篇文章主要介紹了關(guān)于Java中try finally return語(yǔ)句的執(zhí)行順序淺析,需要的朋友可以參考下2017-08-08JDBC程序更新數(shù)據(jù)庫(kù)中記錄的方法
這篇文章主要介紹了JDBC程序更新數(shù)據(jù)庫(kù)中記錄的方法,涉及Java基于JDBC操作數(shù)據(jù)庫(kù)的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10SpringBoot?Security權(quán)限控制自定義failureHandler實(shí)例
這篇文章主要為大家介紹了SpringBoot?Security權(quán)限控制自定義failureHandler實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11