jdk1.7.0_79
創(chuàng)新互聯(lián)公司公司2013年成立,先為蘆溪等服務(wù)建站,蘆溪等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為蘆溪企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
本文實(shí)際上是對上文《簡單談?wù)凾hreadPoolExecutor線程池之submit方法》的一個(gè)延續(xù)或者一個(gè)補(bǔ)充。在上文中提到的submit方法里出現(xiàn)了FutureTask,這不得不停止腳步將方向轉(zhuǎn)向Java的Future模式。
Future是并發(fā)編程中的一種設(shè)計(jì)模式,對于多線程來說,線程A需要等待線程B的結(jié)果,它沒必要一直等待B,可以先拿到一個(gè)未來的Future,等B有了結(jié)果后再取真實(shí)的結(jié)果。
ExecutorService executor = Executors.newSingleThreadExecutor(); Futurefuture = executor.submit(callable); //主線程需要callable線程的結(jié)果,先拿到一個(gè)未來的Future System.out.println(future.get()); //有了結(jié)果后再根據(jù)get方法取真實(shí)的結(jié)果,當(dāng)然如果此時(shí)callable線程如果沒有執(zhí)行完get方法會阻塞執(zhí)行完,如果執(zhí)行完則直接返回結(jié)果或拋出異常
也就是說,F(xiàn)uture它代表一個(gè)異步計(jì)算的結(jié)果。
上面就代表了Future模式的執(zhí)行原理,根據(jù)網(wǎng)上的例子,我們可以來自己實(shí)現(xiàn)一個(gè)Future模式。
package com.future; /** * 數(shù)據(jù)結(jié)果 * Created by yulinfeng on 6/18/17. */ public interface Data { String getResult() throws InterruptedException; }
package com.future; /** * 結(jié)果的真實(shí)計(jì)算過程 * Created by yulinfeng on 6/18/17. */ public class RealData implements Data { protected String data; public RealData(String data) { try { System.out.println("正在計(jì)算結(jié)果"); Thread.sleep(3000); //模擬計(jì)算 } catch (InterruptedException e) { e.printStackTrace(); } this.data = data + “ world”; } public String getResult() throws InterruptedException { return data; } }
package com.future; /** * 真實(shí)結(jié)果RealData的代理 * Created by yulinfeng on 6/18/17. */ public class FutureData implements Data { RealData realData = null; //對RealData的封裝,代理了RealData boolean isReady = false; //真實(shí)結(jié)果是否已經(jīng)準(zhǔn)備好 public synchronized void setResultData(RealData realData) { if (isReady) { return; } this.realData = realData; isReady = true; notifyAll(); //realData已經(jīng)被注入到了futureData中,通知getResult方法 } public synchronized String getResult() throws InterruptedException { if (!isReady) { wait(); //數(shù)據(jù)還未計(jì)算好,阻塞等待 } return realData.getResult(); } }
package com.future; /** * Client主要完成的功能包括:1. 返回一個(gè)FutureData;2.開啟一個(gè)線程用于構(gòu)造RealData * Created by yulinfeng on 6/18/17. */ public class Client { public Data request(final String string) { final FutureData futureData = new FutureData(); /*計(jì)算過程比較慢,單獨(dú)放到一個(gè)線程中去*/ new Thread(new Runnable() { public void run() { RealData realData = new RealData(string); futureData.setResultData(realData); } }).start(); return futureData; //先返回一個(gè)“假”的futureData } }
/** * 負(fù)責(zé)調(diào)用Client發(fā)起請求,并使用返回的數(shù)據(jù)。 * Created by yulinfeng on 6/18/17. */ public class Main { public static void main(String[] args) throws InterruptedException { Client client = new Client(); System.out.println("準(zhǔn)備計(jì)算結(jié)果"); Data data = client.request("hello"); //立即返回一個(gè)“假”的futureData,可以不用阻塞的等待數(shù)據(jù)返回,轉(zhuǎn)而執(zhí)行其它任務(wù) System.out.println("執(zhí)行其它任務(wù)"); Thread.sleep(3000); //模擬執(zhí)行其它任務(wù) System.out.println("數(shù)據(jù)的計(jì)算結(jié)果為:" + data.getResult()); } }
仔細(xì)閱讀以上程序?qū)uture模式的實(shí)現(xiàn)不難發(fā)現(xiàn),F(xiàn)uture模式是異步請求和代理模式的結(jié)合。當(dāng)然在JDK中已經(jīng)為我們實(shí)現(xiàn)好了Future模式。
修改RealData類:
package com.future; import java.util.concurrent.Callable; /** * 結(jié)果的真實(shí)計(jì)算過程 * Created by yulinfeng on 6/18/17. */ public class RealData2 implements Callable{ protected String data; public RealData2(String data) { this.data = data; } public String call() throws Exception { try { System.out.println("正在計(jì)算結(jié)果"); Thread.sleep(2000); //模擬計(jì)算結(jié)果 } catch (InterruptedException e) { e.printStackTrace(); } this.data = data + " world"; return data; } }
修改Main測試類:
package com.future; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 負(fù)責(zé)調(diào)用Executor的submit,并使用返回的數(shù)據(jù)。 * Created by yulinfeng on 6/18/17. */ public class Main2 { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService client = Executors.newSingleThreadExecutor(); //類似Client System.out.println("準(zhǔn)備計(jì)算結(jié)果"); Futuredata = client.submit(new RealData2("hello")); //類似Client.request System.out.println("執(zhí)行其它任務(wù)"); Thread.sleep(3000); System.out.println("數(shù)據(jù)的計(jì)算結(jié)果為:" + data.get()); } }
現(xiàn)在回到上文還未解決完的AbstractExecutorService#submit方法。
類比上面的Client#request方法,在Client#request中先創(chuàng)建一個(gè)FutureData實(shí)例,而在AbstractExecutorService#submit中則是創(chuàng)建一個(gè)FutureTask實(shí)例,接著Client#request新創(chuàng)建一個(gè)線程用于異步執(zhí)行任務(wù),并直接返回FutureData,而在AbstractExecutorService#submit中同樣也將任務(wù)交給了execute方法,并直接返回FutureTask。當(dāng)然JDK中Future模式的實(shí)現(xiàn)更為復(fù)雜。
在《ThreadPoolExecutor線程池原理及其execute方法》中我們講解了execute方法,在ThreadPoolExecutor$Worker#runWorker方法第1145行中是對task任務(wù)的調(diào)用:
//ThreadPoolExecutor$Worker#runWorker task.run();
submit調(diào)用execute以執(zhí)行run方法,實(shí)際執(zhí)行的是FutureTask中的run方法。在FutureTask#run中,可以看到對任務(wù)Callable類型的task異步的執(zhí)行,以及結(jié)果的保存。
以上這篇老生常談java中的Future模式就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持創(chuàng)新互聯(lián)。