Future模式:对于多线程来说,如果线程A要等待线程B到结果,那么线程A没有必要等待线程B,直到B有结果,可以先拿到一个未来到Future,等B有结果时再取真实值。
核心:去除了主函数等待时间,并使得原本需要等待的时间段可以用于处理其他的业务逻辑。
在多线程中经常举的一个例子就是:网络图片的下载,刚开始是通过模糊的图片来代替最后的图片,等下载图片的线程下载完图片后在替换。而在这个过程中可以做一些其他的事情。
首先客户端向服务器请求RealSubject,但是这个资源的创建是非常耗时的,怎么办呢?这种情况下,首先返回Client一个FutureSubject,以满足客户端的需求,于此同时呢,Future会通过另外一个Thread 去构造一个真正的资源,资源准备完毕之后,在给future一个通知。如果客户端急于获取这个真正的资源,那么就会阻塞客户端的其他所有线程,等待资源准备完毕。
公共数据接口,FutureData和RealData都要实现。
/**
* @Description: 公共的data数据结果
*
* @Author: mark
* @Date: 2019/4/8 11:56 PM
*/
public abstract class Data {
/**
* method description: 返回线程执行结果
*
* @param:
* @return: String
*/
public abstract String getRequest();
}
当有线程想要获取到RealData的时候,程序会进行阻塞。等到realData被注入的时候才会使用getRequest方法。
public class FutureData extends Data {
//读取结果
private volatile static boolean flag = false;
private RealData realData;
public synchronized void setRealData(RealData realData){
//如果已经获取到结果,直接返回
if(flag){
return;
}
//否则获取真实结果
this.realData = realData;
flag = true;
notify();
}
@Override
public synchronized String getRequest() {
while(!flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return realData.getRequest();
}
}
获取真实数据:
public class RealData extends Data {
private String result;
//发送请求
public RealData(String requestData){
System.out.println("正在使用data:" + requestData + "网络请求数据,耗时操作需要等待.");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("操作完毕,获取结果");
this.result = "ok";
}
@Override
public String getRequest() {
return result;
}
}
FutureClient 客户端:
public class FutureClient {
public Data request(String reqStr){
FutureData futureData = new FutureData();
new Thread(new Runnable() {
@Override
public void run() {
RealData realData = new RealData(reqStr);
futureData.setRealData(realData);
}
}).start();
return futureData;
}
}
调用者:
public class Test {
public static void main(String[] args) {
FutureClient futureClient = new FutureClient();
Data request = futureClient.request("reqData");
System.out.println("请求发送成功");
System.out.println("主线程执行其他任务");
String result = request.getRequest();
System.out.println("result: " + result);
}
}
调用者请求资源,futureClient.request("reqData"); 完成对数据的准备当要获取资源的时候,request.getRequest() ,如果资源没有准备好flag = false;那么就会阻塞该线程。直到资源获取然后该线程被唤醒。