Java多線程開發(fā)工具之CompletableFuture的應(yīng)用詳解
做Java編程,難免會遇到多線程的開發(fā),但是JDK8這個(gè)CompletableFuture類很多開發(fā)者目前還沒聽說過,但是這個(gè)類實(shí)在是太好用了,了解它的一些用法后相信你會對它愛不釋手(呸渣男,咋對誰都愛不釋手呢),好了我先簡單舉個(gè)列子,告訴你用它有多好。Single Dog拿一個(gè)Appointment來舉個(gè)列子,如下:
/**
* 女神化完妝之后,還需要一小會選衣服,不過分吧。
* 也就是說我們現(xiàn)在有2個(gè)異步任務(wù),第一個(gè)是化妝,第二個(gè)是選衣服。
* 選衣服要在化妝完成之后進(jìn)行,這兩個(gè)任務(wù)是串行
*/
public static void main(String[] args) {
// 線程池我前面的文章聊過,怎么配置可以去了解一下
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() + "-女神,開始化妝了");
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 + "我開始選衣服啦,好了叫你!");
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ù)也可以理解為我們開發(fā)中要實(shí)現(xiàn)的不同功能,看明白前面的列子了吧?用它來寫多線程運(yùn)用的多絲滑。那我們就先講一下它的核心的靜態(tài)的方法,推薦用它的靜態(tài)方法不要直接new對象。
1:無返回值的靜態(tài)方法:
?public static CompletableFuture<Void> runAsync(Runnable runnable)。
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) 。
上面一個(gè)2個(gè)方法,如果沒有指定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)
如果開始的代碼你還看不懂那介紹了上面的幾個(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());好了講過它的使用方法了那我們就聊一下它的幾個(gè)使用的場景,開發(fā)中這寫場景應(yīng)該會使用到。
?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é)果,注意我上面沒說B一定要在A執(zhí)行以后執(zhí)行。

場景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é)果,開發(fā)中的經(jī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è)場景那就寫一個(gè)在開發(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)用相信你可以在你的開發(fā)中進(jìn)行套用,然后靈活的運(yùn)用。當(dāng)然這個(gè)類還有很多的方法,我這里只寫了部分介紹了部分場景作為一個(gè)引子,如果想了解它的更多的應(yīng)用可以看它的API的文檔。
到此這篇關(guān)于Java多線程開發(fā)工具之CompletableFuture的應(yīng)用詳解的文章就介紹到這了,更多相關(guān)Java CompletableFuture內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring boot項(xiàng)目沒有mainClass如何實(shí)現(xiàn)打包運(yùn)行
這篇文章主要介紹了spring boot項(xiàng)目沒有mainClass如何實(shí)現(xiàn)打包運(yùn)行,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
利用JWT如何實(shí)現(xiàn)對API的授權(quán)訪問詳解
這篇文章主要給大家介紹了關(guān)于利用JWT如何實(shí)現(xiàn)對API的授權(quán)訪問的相關(guān)資料,需要的朋友可以參考下2018-09-09
詳解spring cloud中使用Ribbon實(shí)現(xiàn)客戶端的軟負(fù)載均衡
這篇文章主要介紹了詳解spring cloud中使用Ribbon實(shí)現(xiàn)客戶端的軟負(fù)載均衡,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01
基于Lucene的Java搜索服務(wù)器Elasticsearch安裝使用教程
Elasticsearch也是用Java開發(fā)的,并作為Apache許可條款下的開放源碼發(fā)布,能夠做到實(shí)時(shí)搜索,且穩(wěn)定、可靠、快速,安裝使用方便,這里我們就來看一下基于Lucene的Java搜索服務(wù)器Elasticsearch安裝使用教程:2016-06-06
在Spring-Boot中如何使用@Value注解注入集合類
這篇文章主要介紹了在Spring-Boot中如何使用@Value注解注入集合類的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Java多線程之Semaphore實(shí)現(xiàn)信號燈
這篇文章主要給大家分享的是Java多線程之Semaphore實(shí)現(xiàn)信號燈的練習(xí),emaphore是計(jì)數(shù)信號量。Semaphore管理一系列許可證。每個(gè)acquire方法阻塞,直到有一個(gè)許可證可以獲得然后拿走一個(gè)許可證;下面一起進(jìn)入文章學(xué)習(xí)Semaphore的具體內(nèi)容2021-10-10
Spring MVC獲取查詢參數(shù)及路徑參數(shù)代碼實(shí)例
這篇文章主要介紹了Spring MVC獲取查詢參數(shù)及路徑參數(shù)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02

