一、Future模式
Future的意思是未來、期貨,假設有一個方法需要花費很長時間才能獲取運行結果,那麼,與其一直等待結果,不如先拿一張“提貨單”,獲取提貨單並不耗費時間,這裏的“提貨單”我們就成爲Future角色。
二、示例程序
在Thread-Per-Meaasge模式中,我們知道在每次發出請求時都創建一個線程的示例程序,其中,程序中沒有返回值。如:
new Thread() { public void run() { helper.handle(count, c); } }.start();
在Future模式中,程序一旦發出請求,就會立即獲得返回值,也就說,會有如下的返回值:
Data data = host.request(10, 'A');
這裏的返回值data並非請求的運行結果,爲了獲得請求的運行結果。通過線程會調用data的getContent方法去獲取運行結果:
data.getContent();
1.類和接口的一覽表
類名 | 說明 |
---|---|
Main.java | 向Host發出請求並獲取數據的類 |
Host.java | 向請求返回FutureData的實例的類 |
Data.java | 表示訪問數據的方法的接口,由FutureData和RealData實現該接口 |
FutureData.java | 表示RealData的“提貨單”的類,其他線程會創建RealData的實例 |
RealData.java | 表示實際數據的類,構造函數的處理會花費很長時間 |
2.示例程序的類圖
3.實例程序的時序圖
4.Main.java
package com.viagra.Future_Pattern.Lesson1;
/**
* @Auther: viagra
* @Date: 2019/11/19 19:49
* @Description:
*/
public class Main {
public static void main(String[] args) {
/**
* Main類會調用request方法三次,接着它會接收三個Data(data1、data2、data3)作爲返回值
* 這三個返回值實際上都是FutureData的實例,無需花費時間即可獲取它們,類似蛋糕的提貨單
* 然後爲了表示Main類去執行了其他操作,我們讓其sleep2s,接下來,分別調用之前接收到的返回值data1、data2、data3的getContent方法來獲取真正希望獲取的結果。
*/
System.out.println("Main Begin");
Host host = new Host();
Data data1 = host.request(10, 'A');
Data data2 = host.request(20, 'B');
Data data3 = host.request(30, 'C');
System.out.println("Main otherJob Begin");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("data1 = " + data1.getContent());
System.out.println("data2 = " + data2.getContent());
System.out.println("data3 = " + data3.getContent());
System.out.println("Main End");
}
}
5.Host.java
package com.viagra.Future_Pattern.Lesson1;
/**
* @Auther: viagra
* @Date: 2019/11/19 19:49
* @Description:
*/
public class Host {
/**
* 首先會創建FutureData的實例,接着啓動一個新的線程並在新線程中創建RealData的實例。
* 執行request的線程會做一下三件事情:
* 1.創建FutureData的實例
* 2.啓動一個新線程,用戶創建RealData的實例
* 3.將FutureData的實例作爲返回值返回給調用者
* @param count
* @param c
* @return
*/
public Data request(final int count, final char c) {
System.out.println(" request( " + count + " , " + c + " ), Begin");
//(1)創建FutureData的實例
final FutureData future = new FutureData();
//(2)啓動一個新線程,用戶創建RealData的實例
new Thread(){
public void run(){
RealData realData = new RealData(count ,c);
future.setRealData(realData);
}
}.start();
System.out.println(" request( " + count + " , " + c + " ) End");
//(3)返回FutureData的實例
return future;
}
}
6.Data.java接口
package com.viagra.Future_Pattern.Lesson1;
/**
* @Auther: viagra
* @Date: 2019/11/19 19:49
* @Description:
*/
public interface Data {
/**
* Data接口是表示訪問數據的方法接口,FurureData類和RealData類實現了該接口
* @return
*/
public abstract String getContent();
}
7.FutureData.java
package com.viagra.Future_Pattern.Lesson1;
/**
* @Auther: viagra
* @Date: 2019/11/19 19:49
* @Description:
*/
public class FutureData implements Data {
/**
* readData字段是用戶保存稍後創建完畢的RealData的實例的字段。
* ready字段是表示是否已經爲readData賦值的字段,如果爲true,表示已經爲realData賦值。
* setRealData方法是用戶將RealData的實例賦值給realData字段的方法
* setRealData方法會被Host類的request方法創建新的線程調用
* getContent是用戶獲取實際數據的方法。
*/
private RealData realData = null;
private boolean ready = false;
public synchronized void setRealData(RealData realData) {
if (ready) {
return;
}
this.realData = realData;
this.ready = true;
notifyAll();
}
public synchronized String getContent() {
while (!ready) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return realData.getContent();
}
}
8.RealData.java
package com.viagra.Future_Pattern.Lesson1;
/**
* @Auther: viagra
* @Date: 2019/11/19 19:49
* @Description:
*/
public class RealData implements Data {
/**
* 是一個需要花費很長時間才能創建實例的類。
* getContent方法的處理僅僅是返回content字段的內容
*/
private final String content;
public RealData(int count, char c) {
System.out.println(" making RealData ( " + count + " , " + c + " ) Begin");
char[] buffer = new char[count];
for (int i = 0; i < count; i++) {
buffer[i] = c;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(" making RealData ( " + count + " , " + c + " ) End");
this.content = new String(buffer);
}
public String getContent() {
return content;
}
}
9.運行示例程序
Main Begin
request( 10 , A ), Begin
request( 10 , A ) End
request( 20 , B ), Begin
request( 20 , B ) End
request( 30 , C ), Begin
making RealData ( 10 , A ) Begin
making RealData ( 30 , C ) Begin
request( 30 , C ) End
Main otherJob Begin
making RealData ( 20 , B ) Begin
making RealData ( 10 , A ) End
data1 = AAAAAAAAAA
making RealData ( 20 , B ) End
data2 = BBBBBBBBBBBBBBBBBBBB
making RealData ( 30 , C ) End
data3 = CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
Main End
3.Future模式中的角色
1.Client(請求者)
Client角色向Host角色發出請求(request)並會立即接收到請求的處理結果(返回值),是實例程序中的Main類。
2.Host
Host角色會創建新的線程,並開始在新線程中創建ReakData角色,同時,它會將Future角色返回給Clinet角色,是示例程序中的Host類。
3.VirtualData(虛擬數據)
VirtualData角色是讓Future角色與RealData角色具有一致性的角色,是示例程序中的Data接口。
4.RealData(真實數據)
ReakData角色是表示真是數據的角色,是示例程序中的RealData類。
5.Futrue(期貨)
Future角色是RealData角色的“提貨者”,由Host角色傳遞給Client角色,從程序行爲上看,對Client角色而言,Future角色就是VirtureData角色。是示例程序中的FutureData類。