篇文章為大家?guī)碛嘘P(guān)Future模式的多線程異步調(diào)用的詳細(xì)介紹。大部分命令行知識(shí)點(diǎn)都是大家經(jīng)常用到的,為此分享給大家做個(gè)參考。一起跟隨小編過來看看吧。
公司主營(yíng)業(yè)務(wù):網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)公司推出臨邑免費(fèi)做網(wǎng)站回饋大家。
當(dāng)我們調(diào)用一個(gè)函數(shù)的時(shí)候,如果這個(gè)函數(shù)的執(zhí)行過程是很耗時(shí)的,我們就必須要等待,但是我們有時(shí)候并不急著要這個(gè)函數(shù)返回的結(jié)果。因此,我們可以讓被調(diào)者立即返回,讓他在后臺(tái)慢慢的處理這個(gè)請(qǐng)求。對(duì)于調(diào)用者來說,則可以先處理一些其他事情,在真正需要數(shù)據(jù)的時(shí)候再去嘗試獲得需要的數(shù)據(jù)(這個(gè)真正需要數(shù)據(jù)的位置也就是上文提到的阻塞點(diǎn))。這也是Future模式的核心思想:異步調(diào)用。
到了這里,你可能會(huì)想CountDownLatch不是也可以實(shí)現(xiàn)類似的功能的嗎?也是可以讓耗時(shí)的任務(wù)通過子線程的方式去執(zhí)行,然后設(shè)置一個(gè)阻塞點(diǎn)等待返回的結(jié)果,情況貌似是這樣的!但有時(shí)發(fā)現(xiàn)CountDownLatch只知道子線程的完成情況是不夠的,如果在子線程完成后獲取其計(jì)算的結(jié)果,那CountDownLatch就有些捉襟見襯了,所以JDK提供的Future類,不僅可以在子線程完成后收集其結(jié)果,還可以設(shè)定子線程的超時(shí)時(shí)間,避免主任務(wù)一直等待。
看到這里,似乎恍然大悟了!CountDownLatch無法很好的洞察子線程執(zhí)行的結(jié)果,使用Future就可以完成這一操作,那么Future何方神圣!下邊我們就細(xì)細(xì)聊一下。
雖然,F(xiàn)uture模式不會(huì)立即返回你需要的數(shù)據(jù),但是,他會(huì)返回一個(gè)契約 ,以后在使用到數(shù)據(jù)的時(shí)候就可以通過這個(gè)契約獲取到需要的數(shù)據(jù)。
上圖顯示的是一個(gè)串行程序調(diào)用的流程,可以看出當(dāng)有一個(gè)程序執(zhí)行的時(shí)候比較耗時(shí)的時(shí)候,其他程序必須等待該耗時(shí)操作的結(jié)束,這樣的話客戶端就必須一直等待,知道返回?cái)?shù)據(jù)才執(zhí)行其他的任務(wù)處理。
上圖展示的是Future模式流程圖,在廣義的Future模式中,雖然獲取數(shù)據(jù)是一個(gè)耗時(shí)的操作,但是服務(wù)程序不等數(shù)據(jù)完成就立即返回客戶端一個(gè)偽造的數(shù)據(jù)(就是上述說的“契約”),實(shí)現(xiàn)了Future模式的客戶端并不急于對(duì)其進(jìn)行處理,而是先去處理其他業(yè)務(wù),充分利用了等待的時(shí)間,這也是Future模式的核心所在,在完成了其他數(shù)據(jù)無關(guān)的任務(wù)之后,最后在使用返回比較慢的Future數(shù)據(jù)。這樣在整個(gè)調(diào)用的過程中就不會(huì)出現(xiàn)長(zhǎng)時(shí)間的等待,充分利用時(shí)間,從而提高系統(tǒng)效率。
1、Future主要角色
2、Future的核心結(jié)構(gòu)圖如下:
上述的流程就是說:Data為核心接口,這是客戶端希望獲取的數(shù)據(jù),在Future模式中,這個(gè)Data接口有兩個(gè)重要的實(shí)現(xiàn),分別是:RealData和FutureData。RealData就是真實(shí)的數(shù)據(jù),F(xiàn)utureData他是用來提取RealData真是數(shù)據(jù)的接口實(shí)現(xiàn),用于立即返回得到的,他實(shí)際上是真實(shí)數(shù)據(jù)RealData的代理,封裝了獲取RealData的等待過程。
說了這些理論的東西,倒不如直接看代碼來的直接些,請(qǐng)看代碼!
主要包含以下5個(gè)類,對(duì)應(yīng)著Future模式的主要角色:
1、Data接口
/**
* 返回?cái)?shù)據(jù)的接口
*/
public interface Data {
String getResult();
}
2、FutureData代碼
/**
* Future數(shù)據(jù),構(gòu)造很快,但是是一個(gè)虛擬的數(shù)據(jù),需要裝配RealData
*/
public class FutureData implements Data {
private RealData realData = null;
private boolean isReady = false;
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
@Override
public String getResult() {
while (!isReady) {
try {
lock.lock();
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
return realData.getResult();
}
public void setRealData(RealData realData) {
lock.lock();
if (isReady) {
return;
}
this.realData = realData;
isReady = true;
condition.signal();
lock.unlock();
}
}
3、RealData代碼
public class RealData implements Data {
private String result;
public RealData(String param) {
StringBuffer sb = new StringBuffer();
sb.append(param);
try {
//模擬構(gòu)造真實(shí)數(shù)據(jù)的耗時(shí)操作
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
result = sb.toString();
}
@Override
public String getResult() {
return result;
}
}
4、Client代碼
public class Client {
public Data request(String param) {
//立即返回FutureData
FutureData futureData = new FutureData();
//開啟ClientThread線程裝配RealData
new Thread(() -> {
{
//裝配RealData
RealData realData = new RealData(param);
futureData.setRealData(realData);
}
}).start();
return futureData;
}
}
5、Main
/**
* 系統(tǒng)啟動(dòng),調(diào)用Client發(fā)出請(qǐng)求
*/
public class Main {
public static void main(String[] args) {
Client client = new Client();
Data data = client.request("Hello Future!");
System.out.println("請(qǐng)求完畢!");
try {
//模擬處理其他業(yè)務(wù)
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("真實(shí)數(shù)據(jù):" + data.getResult());
}
}
6、執(zhí)行結(jié)果:
上述實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的Future模式的實(shí)現(xiàn),因?yàn)檫@是一個(gè)很常用的模式,在JDK中也給我們提供了對(duì)應(yīng)的方法和接口,先看一下實(shí)例:
public class RealData implements Callable {
private String result;
public RealData(String result) {
this.result = result;
}
@Override
public String call() throws Exception {
StringBuffer sb = new StringBuffer();
sb.append(result);
//模擬耗時(shí)的構(gòu)造數(shù)據(jù)過程
Thread.sleep(5000);
return sb.toString();
}
}
這里的RealData 實(shí)現(xiàn)了Callable接口,重寫了call方法,在call方法里邊實(shí)現(xiàn)了構(gòu)造真實(shí)數(shù)據(jù)耗時(shí)的操作。
public class FutureMain {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask<>(new RealData("Hello"));
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.execute(futureTask);
System.out.println("請(qǐng)求完畢!");
try {
Thread.sleep(2000);
System.out.println("這里經(jīng)過了一個(gè)2秒的操作!");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("真實(shí)數(shù)據(jù):" + futureTask.get());
executorService.shutdown();
}
}
執(zhí)行結(jié)果:
上述代碼,通過:FutureTask
FutureTask實(shí)現(xiàn)了RunnableFuture接口,RunnableFuture接口繼承了Future和Runnable接口。因?yàn)镽unnableFuture實(shí)現(xiàn)了Runnable接口,因此FutureTask可以提交給Executor進(jìn)行執(zhí)行,F(xiàn)utureTask有兩個(gè)構(gòu)造方法,如下:
構(gòu)造方法1,參數(shù)為Callable:
構(gòu)造方法2,參數(shù)為Runnable:
上述的第二個(gè)構(gòu)造方法,傳入的是Runnable接口的話,會(huì)通過Executors.callable()方法轉(zhuǎn)化為Callable,適配過程如下:
這里為什么要將Runnable轉(zhuǎn)化為Callable哪?首先看一下兩者之間的區(qū)別:
(1) Callable規(guī)定的方法是call(),Runnable規(guī)定的方法是run();
(2) Callable的任務(wù)執(zhí)行后可返回值,而Runnable的任務(wù)是不能返回值得;
(3) call()方法可以拋出異常,run()方法不可以;
(4) 運(yùn)行Callable任務(wù)可以拿到一個(gè)Future對(duì)象,F(xiàn)uture 表示異步計(jì)算的結(jié)果。
最關(guān)鍵的是第二點(diǎn),就是Callable具有返回值,而Runnable沒有返回值。Callable提供了檢查計(jì)算是否完成的方法,以等待計(jì)算的完成,并獲取計(jì)算的結(jié)果。
計(jì)算完成后只能使用 get 方法來獲取結(jié)果,如果線程沒有執(zhí)行完,F(xiàn)uture.get()方法可能會(huì)阻塞當(dāng)前線程的執(zhí)行;如果線程出現(xiàn)異常,F(xiàn)uture.get()會(huì)throws InterruptedException或者ExecutionException;如果線程已經(jīng)取消,會(huì)拋出CancellationException。取消由cancel 方法來執(zhí)行。isDone確定任務(wù)是正常完成還是被取消了。
一旦計(jì)算完成,就不能再取消計(jì)算。如果為了可取消性而使用 Future 但又不提供可用的結(jié)果,則可以聲明Future> 形式類型、并返回 null 作為底層任務(wù)的結(jié)果。
以上就是Future模式的多線程異步調(diào)用的匯總,內(nèi)容較為全面,而且我也相信有相當(dāng)?shù)囊恍┕ぞ呖赡苁俏覀內(nèi)粘9ぷ骺赡軙?huì)見到或用到的。通過這篇文章,希望你能收獲更多。