Future模式简介:在处理某些比较复杂的业务逻辑时,我们需要首先返回一个虚拟结果(即Future的含义),然后再Future中创建线程去执行其他的方法,如果这个虚拟的结果不会立即使用(比如在调用这个结果的某个方法前需要执行其他业务耗时操作),那么在执行真实结果的耗时会和其他业务耗时操作同时执行,从而节约了时间,这就是Future模式的出发点。
代码实现:
package thread.future模式;
public interface Data {
public String getRequest();
}
简单接口,只有一个getRequest方法,以后我们的模拟结果类(FutureData)和真实结果类(RealData)都会实现这个接口
package thread.future模式;
public class RealData implements Data {
public RealData() {
System.out.println("缓慢初始化...");
try {
//模拟初始化复杂业务对象的时间
Thread.sleep(5000);
System.out.println("RealData初始化完毕");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public String getRequest() {
String result = null;
//模拟获得结果所需要的时间,这里将是以后最为复杂的业务逻辑部分
try {
Thread.sleep(6000);
result = "结果查询完毕,并返回";
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
}
RealData类是我们要执行真实数据的类,其中getRequest是我们主要的业务方法,需要耗费一定的时间(初始化5秒,执行方法6秒)
package thread.future模式;
public class FutureData implements Data {
private RealData realData;
private boolean isReady = false;
private Object lock = new Object();
public void setRealData(RealData realData) {
synchronized (lock) {
if(isReady){
return;
}
this.realData = realData;
System.out.println("设置RealData已经成功");
isReady = true;
lock.notify();
}
}
@Override
public String getRequest() {
synchronized (lock) {
while(!isReady) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return this.realData.getRequest();
}
}
}
FutureData类是我们的虚拟结果类,可以看到setRealDatat方法就是将参数中初始化成功的RealData对象设置到FutureData的一个成员变量中,并发出notify通知,同时设置flag为成功,getRequest方法在setRealData方法执行成功之前一直都会处于一个阻塞状态,直到接收到notify通知会调用RealData的getRequest方法返回真实数据
package thread.future模式;
public class FutureClient {
public Data getData() {
final FutureData futureData = new FutureData();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("多线程启动...");
RealData realData = new RealData();
futureData.setRealData(realData);
}
}).start();
return futureData;
}
}
FutureClient简单的代理对象方法,作为主业务逻辑获取Data的伪代理对象,在其中启动一个线程调用真实数据方法的创建和业务数据计算,并赋给RealData,实际返回的是RealData对象
package thread.future模式;
public class Main {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
FutureClient client = new FutureClient();
Data d = client.getData();
//模拟其他业务方法耗时
Thread.sleep(5000);
//使用data数据
System.out.println(d.getRequest());
long end = System.currentTimeMillis();
System.out.println("总计耗时:" + (end-start) + "秒");
}
}
模拟的调用方法,可以看到先执行了FutureClient的getData()方法,返回一个Data(实际上是一个虚拟对象)对象,实际上我们后台新创建一个线程获取真实数据对象并计算结果,同时,会执行本类中耗时的业务逻辑
执行结果
多线程启动...
缓慢初始化...
RealData初始化完毕
设置RealData已经成功
结果查询完毕,并返回
总计耗时:11003秒
业务总耗时(不使用多线程):RealData初始化5秒业务逻辑5秒,Main方法5秒总计16秒
使用这种设计模式总耗时:11秒
这样,在Controller层做实现时,就不必关心封装的代码到底是怎么写的,对某些业务场景有一定的适用性。