Java中的Future獲取任務(wù)返回值詳解
Future獲取任務(wù)返回值
submit方法簽名
在向線程池ThreadPoolExecutor提交任務(wù)時,一般為了方便操作采用execute提交任務(wù),這時線程其實是無返回值的,但是在生產(chǎn)中為了應(yīng)對各種各樣的需求,獲取線程返回值是必不可少的,所以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);
很明顯三個submit提交任務(wù)的返回值都是Future,其實Future是一個接口,F(xiàn)uture內(nèi)部提供五大方法
// 任務(wù)取消操作 參數(shù)是允許中斷正在運行的線程
boolean cancel(boolean mayInterruptIfRunning);
// 判斷任務(wù)是否取消
boolean isCancelled();
// 判斷任務(wù)是否結(jié)束
boolean isDone();
// 阻塞式的獲取任務(wù)返回結(jié)果
V get() throws InterruptedException, ExecutionException;
// 支持超時功能
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;需要注意的是,兩個get都是阻塞式獲取線程返回結(jié)果的,所以當調(diào)用get后,調(diào)用線程就會睡眠,只有當任務(wù)返回結(jié)果后才會喚醒線程往下執(zhí)行。
submit方法說明
submit的三大提交方法是有所不同的,不同的場景對應(yīng)不同的方法。
- submit(Runnable task)方法參數(shù)是Runnable接口,實現(xiàn)Runnable的線程是沒有返回值的,所以這個submit雖然能夠返回Future對象,調(diào)用其get方法還是返回null值的,F(xiàn)uture只能當斷言使用,類似于Thread.join方法。
- submit(Callable task)方法參數(shù)是Callable接口(線程如果實現(xiàn)Callable接口,那么要求實現(xiàn)call()方法,這個方法支持返回值),顯然實現(xiàn)Callable的線程是能夠返回值的,所以這個submit能夠返回Future對象,同時調(diào)用get方法還能得到返回值。
- Future submit(Runnable task, T result);這個方法的簽名稍微有點復(fù)雜,和第一種提交方式相比多了result對象,這個對象其實就是后面Future.get出來的返回值,result可以認為是主線程和子線程的橋梁,通過result實現(xiàn)主線程和子線程的通信,可能這樣說還是有些模糊,可以參考如下示例思考。
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);
}
}
// 實現(xiàn)線程方法
class Task implements Runnable{
// 非常重要的一般 相當于是參數(shù)傳遞的形式,可以到線程中修改
Apple apple;
public Task(Apple apple){
this.apple = apple;
}
@Override
public void run() {
// 在線程中可以操作傳入的對象
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的實現(xiàn)-FutureTask
Future只是一個接口,有接口了必須介紹下它的具體實現(xiàn)FutureTask,F(xiàn)utureTask是一個工具類,這個工具類有兩個構(gòu)造函數(shù),簽名如下
public FutureTask(Callable<V> callable) public FutureTask(Runnable runnable, V result)
FutureTask實現(xiàn)了Runnable,和Future接口,由于現(xiàn)實了Runnable接口,所以FutureTask可以作為參數(shù)提交給線程池ThreadPoolExecutor,也可以作為構(gòu)造參數(shù)傳遞給Thread,而FutureTask還實現(xiàn)了Future就可以獲取線程的返回值,所以我們可以得到FutureTask的兩種用法。
方法一:作為參數(shù)提交到線程池中執(zhí)行。
// 定義對象
FutureTask<Integer> task = new FutureTask(()->{
return 1+2;
});
// 定義線程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 不要使用這里的返回值,就算是FutureTask實現(xiàn)了Future對象,
// 但是Future也現(xiàn)實了Runnable接口返回值為空
Future<?> submit = executorService.submit(task);
// 返回值獲取
System.out.println(task.get());
executorService.shutdown();方法二:作為構(gòu)造參數(shù)傳遞給Thread
// 定義對象
FutureTask<Integer> task = new FutureTask(()->{
return 1+2;
});
// 線程構(gòu)造方法,傳入Runnable的子類
Thread thread = new Thread(task);
thread.start();
System.out.println(task.get());FutureTask的實戰(zhàn)
在數(shù)學(xué)家華羅庚的文章中提出燒水泡茶的最優(yōu)解,如下所示

用到編程世界中,那么將上述最優(yōu)解可以拆分為兩個線程去執(zhí)行

線程A需要完成洗水壺,燒水的工作,完成后等待線程B將洗茶壺,洗茶杯,拿茶葉三個步驟做完,所以線程A在內(nèi)部需要等待線程B執(zhí)行完畢才能完成最后泡茶的工作,這里可以采用Thread.join,CountDownLatch,F(xiàn)uture都可以實現(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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring?Data?JPA系列JpaSpecificationExecutor用法詳解
這篇文章主要為大家介紹了Spring?Data?JPA系列JpaSpecificationExecutor用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09
SpringBoot?+DynamicDataSource切換多數(shù)據(jù)源的全過程
這篇文章主要介紹了SpringBoot?+DynamicDataSource切換多數(shù)據(jù)源的全過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
java 獲取數(shù)據(jù)庫連接的實現(xiàn)代碼
本篇文章是對在java中獲取數(shù)據(jù)庫連接的實現(xiàn)代碼進行了詳細的分析介紹,需要的朋友參考下2013-05-05
Java concurrency之公平鎖(二)_動力節(jié)點Java學(xué)院整理
這篇文章主要為大家詳細介紹了Java concurrency之公平鎖的第二篇內(nèi)容,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06
Java微信公眾平臺開發(fā)(3) 接收消息的分類及實體的創(chuàng)建
這篇文章主要為大家詳細介紹了Java微信公眾平臺開發(fā)第三步,接收消息的分類及實體的創(chuàng)建,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
SpringBoot高版本修改為低版本時測試類報錯的解決方案
這篇文章主要介紹了SpringBoot高版本修改為低版本時測試類報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09

