一、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类。