jdk1.7.0_79
本文實際上是對上文《簡單談談ThreadPoolExecutor線程池之submit方法》的一個延續(xù)或者一個補充。在上文中提到的submit方法里出現(xiàn)了FutureTask,這不得不停止腳步將方向轉(zhuǎn)向Java的Future模式。
Future是并發(fā)編程中的一種設計模式,對于多線程來說,線程A需要等待線程B的結果,它沒必要一直等待B,可以先拿到一個未來的Future,等B有了結果后再取真實的結果。
1
2
3
|
ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(callable); //主線程需要callable線程的結果,先拿到一個未來的Future System.out.println(future.get()); //有了結果后再根據(jù)get方法取真實的結果,當然如果此時callable線程如果沒有執(zhí)行完get方法會阻塞執(zhí)行完,如果執(zhí)行完則直接返回結果或拋出異常 |
也就是說,Future它代表一個異步計算的結果。
上面就代表了Future模式的執(zhí)行原理,根據(jù)網(wǎng)上的例子,我們可以來自己實現(xiàn)一個Future模式。
1
2
3
4
5
6
7
8
9
|
package com.future; /** * 數(shù)據(jù)結果 * Created by yulinfeng on 6/18/17. */ public interface Data { String getResult() throws InterruptedException; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.future; /** * 結果的真實計算過程 * Created by yulinfeng on 6/18/17. */ public class RealData implements Data { protected String data; public RealData(String data) { try { System.out.println( "正在計算結果" ); Thread.sleep( 3000 ); //模擬計算 } catch (InterruptedException e) { e.printStackTrace(); } this .data = data + “ world”; } public String getResult() throws InterruptedException { return data; } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package com.future; /** * 真實結果RealData的代理 * Created by yulinfeng on 6/18/17. */ public class FutureData implements Data { RealData realData = null ; //對RealData的封裝,代理了RealData boolean isReady = false ; //真實結果是否已經(jīng)準備好 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ù)還未計算好,阻塞等待 } return realData.getResult(); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.future; /** * Client主要完成的功能包括:1. 返回一個FutureData;2.開啟一個線程用于構造RealData * Created by yulinfeng on 6/18/17. */ public class Client { public Data request( final String string) { final FutureData futureData = new FutureData(); /*計算過程比較慢,單獨放到一個線程中去*/ new Thread( new Runnable() { public void run() { RealData realData = new RealData(string); futureData.setResultData(realData); } }).start(); return futureData; //先返回一個“假”的futureData } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/** * 負責調(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( "準備計算結果" ); Data data = client.request( "hello" ); //立即返回一個“假”的futureData,可以不用阻塞的等待數(shù)據(jù)返回,轉(zhuǎn)而執(zhí)行其它任務 System.out.println( "執(zhí)行其它任務" ); Thread.sleep( 3000 ); //模擬執(zhí)行其它任務 System.out.println( "數(shù)據(jù)的計算結果為:" + data.getResult()); } } |
仔細閱讀以上程序?qū)uture模式的實現(xiàn)不難發(fā)現(xiàn),F(xiàn)uture模式是異步請求和代理模式的結合。當然在JDK中已經(jīng)為我們實現(xiàn)好了Future模式。
修改RealData類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.future; import java.util.concurrent.Callable; /** * 結果的真實計算過程 * Created by yulinfeng on 6/18/17. */ public class RealData2 implements Callable<String> { protected String data; public RealData2(String data) { this .data = data; } public String call() throws Exception { try { System.out.println( "正在計算結果" ); Thread.sleep( 2000 ); //模擬計算結果 } catch (InterruptedException e) { e.printStackTrace(); } this .data = data + " world" ; return data; } } |
修改Main測試類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package com.future; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 負責調(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( "準備計算結果" ); Future<String> data = client.submit( new RealData2( "hello" )); //類似Client.request System.out.println( "執(zhí)行其它任務" ); Thread.sleep( 3000 ); System.out.println( "數(shù)據(jù)的計算結果為:" + data.get()); } } |
現(xiàn)在回到上文還未解決完的AbstractExecutorService#submit方法。
類比上面的Client#request方法,在Client#request中先創(chuàng)建一個FutureData實例,而在AbstractExecutorService#submit中則是創(chuàng)建一個FutureTask實例,接著Client#request新創(chuàng)建一個線程用于異步執(zhí)行任務,并直接返回FutureData,而在AbstractExecutorService#submit中同樣也將任務交給了execute方法,并直接返回FutureTask。當然JDK中Future模式的實現(xiàn)更為復雜。
在《ThreadPoolExecutor線程池原理及其execute方法》中我們講解了execute方法,在ThreadPoolExecutor$Worker#runWorker方法第1145行中是對task任務的調(diào)用:
1
2
|
//ThreadPoolExecutor$Worker#runWorker task.run(); |
submit調(diào)用execute以執(zhí)行run方法,實際執(zhí)行的是FutureTask中的run方法。在FutureTask#run中,可以看到對任務Callable類型的task異步的執(zhí)行,以及結果的保存。
以上這篇老生常談java中的Future模式就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持服務器之家。