Java中的Future獲取任務(wù)返回值詳解
Future獲取任務(wù)返回值
submit方法簽名
在向線程池ThreadPoolExecutor提交任務(wù)時(shí),一般為了方便操作采用execute提交任務(wù),這時(shí)線程其實(shí)是無(wú)返回值的,但是在生產(chǎn)中為了應(yīng)對(duì)各種各樣的需求,獲取線程返回值是必不可少的,所以SDK提供另一種任務(wù)提交方式submit,方法簽名如下
// 提交Runnable任務(wù) Future<?> submit(Runnable task); // 提交Callable任務(wù) <T> Future<T> submit(Callable<T> task); // 提交Runnable任務(wù)及結(jié)果引用 <T> Future<T> submit(Runnable task, T result);
很明顯三個(gè)submit提交任務(wù)的返回值都是Future,其實(shí)Future是一個(gè)接口,F(xiàn)uture內(nèi)部提供五大方法
// 任務(wù)取消操作 參數(shù)是允許中斷正在運(yùn)行的線程 boolean cancel(boolean mayInterruptIfRunning); // 判斷任務(wù)是否取消 boolean isCancelled(); // 判斷任務(wù)是否結(jié)束 boolean isDone(); // 阻塞式的獲取任務(wù)返回結(jié)果 V get() throws InterruptedException, ExecutionException; // 支持超時(shí)功能 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
需要注意的是,兩個(gè)get都是阻塞式獲取線程返回結(jié)果的,所以當(dāng)調(diào)用get后,調(diào)用線程就會(huì)睡眠,只有當(dāng)任務(wù)返回結(jié)果后才會(huì)喚醒線程往下執(zhí)行。
submit方法說(shuō)明
submit的三大提交方法是有所不同的,不同的場(chǎng)景對(duì)應(yīng)不同的方法。
- submit(Runnable task)方法參數(shù)是Runnable接口,實(shí)現(xiàn)Runnable的線程是沒有返回值的,所以這個(gè)submit雖然能夠返回Future對(duì)象,調(diào)用其get方法還是返回null值的,F(xiàn)uture只能當(dāng)斷言使用,類似于Thread.join方法。
- submit(Callable task)方法參數(shù)是Callable接口(線程如果實(shí)現(xiàn)Callable接口,那么要求實(shí)現(xiàn)call()方法,這個(gè)方法支持返回值),顯然實(shí)現(xiàn)Callable的線程是能夠返回值的,所以這個(gè)submit能夠返回Future對(duì)象,同時(shí)調(diào)用get方法還能得到返回值。
- Future submit(Runnable task, T result);這個(gè)方法的簽名稍微有點(diǎn)復(fù)雜,和第一種提交方式相比多了result對(duì)象,這個(gè)對(duì)象其實(shí)就是后面Future.get出來(lái)的返回值,result可以認(rèn)為是主線程和子線程的橋梁,通過(guò)result實(shí)現(xiàn)主線程和子線程的通信,可能這樣說(shuō)還是有些模糊,可以參考如下示例思考。
public class Test4 { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newFixedThreadPool(2); Apple apple = new Apple("red apple",5999.9); System.out.println("調(diào)用前==" +apple); Task task = new Task(apple); Future<Apple> submit = executor.submit(task, apple); // 阻塞式獲取 Apple result = submit.get(); System.out.println("調(diào)用前==" + result); } } // 實(shí)現(xiàn)線程方法 class Task implements Runnable{ // 非常重要的一般 相當(dāng)于是參數(shù)傳遞的形式,可以到線程中修改 Apple apple; public Task(Apple apple){ this.apple = apple; } @Override public void run() { // 在線程中可以操作傳入的對(duì)象 apple.setName("green apple"); System.out.println("操作Apple"); } } class Apple{ private String name; private double price; public Apple(String name,double price){ this.name = name; this.price = price; } // 省略get set方法 以及toString方法 }
返回結(jié)果如下
Future的實(shí)現(xiàn)-FutureTask
Future只是一個(gè)接口,有接口了必須介紹下它的具體實(shí)現(xiàn)FutureTask,F(xiàn)utureTask是一個(gè)工具類,這個(gè)工具類有兩個(gè)構(gòu)造函數(shù),簽名如下
public FutureTask(Callable<V> callable) public FutureTask(Runnable runnable, V result)
FutureTask實(shí)現(xiàn)了Runnable,和Future接口,由于現(xiàn)實(shí)了Runnable接口,所以FutureTask可以作為參數(shù)提交給線程池ThreadPoolExecutor,也可以作為構(gòu)造參數(shù)傳遞給Thread,而FutureTask還實(shí)現(xiàn)了Future就可以獲取線程的返回值,所以我們可以得到FutureTask的兩種用法。
方法一:作為參數(shù)提交到線程池中執(zhí)行。
// 定義對(duì)象 FutureTask<Integer> task = new FutureTask(()->{ return 1+2; }); // 定義線程池 ExecutorService executorService = Executors.newFixedThreadPool(3); // 不要使用這里的返回值,就算是FutureTask實(shí)現(xiàn)了Future對(duì)象, // 但是Future也現(xiàn)實(shí)了Runnable接口返回值為空 Future<?> submit = executorService.submit(task); // 返回值獲取 System.out.println(task.get()); executorService.shutdown();
方法二:作為構(gòu)造參數(shù)傳遞給Thread
// 定義對(duì)象 FutureTask<Integer> task = new FutureTask(()->{ return 1+2; }); // 線程構(gòu)造方法,傳入Runnable的子類 Thread thread = new Thread(task); thread.start(); System.out.println(task.get());
FutureTask的實(shí)戰(zhàn)
在數(shù)學(xué)家華羅庚的文章中提出燒水泡茶的最優(yōu)解,如下所示
用到編程世界中,那么將上述最優(yōu)解可以拆分為兩個(gè)線程去執(zhí)行
線程A需要完成洗水壺,燒水的工作,完成后等待線程B將洗茶壺,洗茶杯,拿茶葉三個(gè)步驟做完,所以線程A在內(nèi)部需要等待線程B執(zhí)行完畢才能完成最后泡茶的工作,這里可以采用Thread.join,CountDownLatch,F(xiàn)uture都可以實(shí)現(xiàn),以Future為例。
public class UseFutureTask { public static void main(String[] args) throws ExecutionException, InterruptedException { // 定義線程B的執(zhí)行 FutureTask<String> futureTaskB = new FutureTask<>(new ThreadB()); // 定義線程A的執(zhí)行 FutureTask futureTaskA = new FutureTask(new ThreadA(futureTaskB),null); // 線程執(zhí)行 Thread threadA = new Thread(futureTaskA); Thread threadB = new Thread(futureTaskB); threadA.start(); threadB.start(); futureTaskA.get(); } } // 用于線程A 完成洗水壺 燒水 class ThreadA implements Runnable { FutureTask<String> futureTask; public ThreadA(FutureTask<String> futureTask){ this.futureTask = futureTask; } @Override public void run() { try { System.out.println("ThreadA 洗水壺"); TimeUnit.SECONDS.sleep(1); System.out.println("ThreadA 燒水"); TimeUnit.SECONDS.sleep(15); // 需要獲取線程B的茶葉 String teaName = futureTask.get(); System.out.println("ThreadA 泡茶===="+teaName); } catch (Exception e) { e.printStackTrace(); } } } // 用于線程B 完成洗茶壺 洗茶杯 拿茶葉 需要返回茶葉的 class ThreadB implements Callable<String> { @Override public String call() throws Exception { System.out.println("ThreadB 洗茶壺"); TimeUnit.SECONDS.sleep(1); System.out.println("ThreadB 洗茶杯"); TimeUnit.SECONDS.sleep(2); System.out.println("ThreadB 拿茶葉"); TimeUnit.SECONDS.sleep(1); return "鐵觀音"; } }
執(zhí)行結(jié)果
到此這篇關(guān)于Java中的Future獲取任務(wù)返回值詳解的文章就介紹到這了,更多相關(guān)Future獲取任務(wù)返回值內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring?Data?JPA系列JpaSpecificationExecutor用法詳解
這篇文章主要為大家介紹了Spring?Data?JPA系列JpaSpecificationExecutor用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09SpringBoot?+DynamicDataSource切換多數(shù)據(jù)源的全過(guò)程
這篇文章主要介紹了SpringBoot?+DynamicDataSource切換多數(shù)據(jù)源的全過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01java 獲取數(shù)據(jù)庫(kù)連接的實(shí)現(xiàn)代碼
本篇文章是對(duì)在java中獲取數(shù)據(jù)庫(kù)連接的實(shí)現(xiàn)代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05Java concurrency之公平鎖(二)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了Java concurrency之公平鎖的第二篇內(nèi)容,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Java微信公眾平臺(tái)開發(fā)(3) 接收消息的分類及實(shí)體的創(chuàng)建
這篇文章主要為大家詳細(xì)介紹了Java微信公眾平臺(tái)開發(fā)第三步,接收消息的分類及實(shí)體的創(chuàng)建,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04SpringBoot高版本修改為低版本時(shí)測(cè)試類報(bào)錯(cuò)的解決方案
這篇文章主要介紹了SpringBoot高版本修改為低版本時(shí)測(cè)試類報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09