一、 Future模式理解
先说一下为什么要用future模式:两个任务没有必然的前后关系,如果在一个线程中串行执行,就有些浪费时间,不如让两个线程去并行执行这两个任务,执行完了到主线程去汇报就可以了。(让任务后台运行,不阻塞线程)
则使用Future模式耗费的时间为: max(TimeofTask1,TimeofTask2)。串行的话则是TimeofTask1+TimeofTask2。
接下来使用代码的类图:
先贴出源码,可以先看下源码理解一下,怎么使用就成了future模式。
Interface:
public interfaceData {publicString getResult();
}
RealData:
public class RealData implementsData{protected finalString result;publicRealData(String para) {
StringBuilder sb= newStringBuilder();for (int i = 0; i < 10; i++) {
sb.append(para);
}try{//这里使用sleep,模拟很慢的构造RealData过程
Thread.sleep(100);
}catch(InterruptedException e) {
e.printStackTrace();
}
result=sb.toString();
}
}
FutureData
//FutureData是RealData的包装
public class FutureData implementsData {protected RealData realData = null;protected boolean isReady = false;public synchronized voidsetRealData(RealData realdata){if(isReady){return;
}this.realData =realdata;
isReady= true;//RealData注入完毕以后,通知getResult()
notifyAll();
}
@Overridepublic synchronizedString getResult() {while (!isReady){try{//等待RealData被注入,直到被notify
wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}returnrealData.result;
}
}
View Code
首先我们要明确,RealData是我们真正需要的数据,FutureData只是做了一层封装,可以实现在得到RealData的过程中不阻塞当前线程。
我们重点来看FutureData,就两个方法,暂且把setRealData叫做注入数据方法,getResult是拿到最终数据方法。
一个状态位isReady,等待RealData注入完毕,就可以getResult了。没注入完毕,则阻塞当前线程。
有了这些信息,我们可以这样想,这个构建RealData很费时间,不如把这个构建任务扔到一个线程里去,当前线程去做其他事情。
使用方法:
public classFutureMainByMyself {public Data request(finalString queryStr){//futureData包装了RealData
final FutureData futureData = newFutureData();newThread(){//RealData构建很慢,放在一个线程里慢慢去构建
@Overridepublic voidrun() {
RealData realData= newRealData(queryStr);
futureData.setRealData(realData);
}
}.start();
returnfutureData;
}public static voidmain(String[] args) {
FutureMainByMyself client= newFutureMainByMyself();
Data data= client.request("name");
System.out.println("请求完毕");//这里才是真实的数据
try{//这里的sleep代表了其他的业务逻辑,//在处理这些业务逻辑的同时,RealData被创建,从而充分利用了时间
System.out.println(LocalTime.now());
Thread.sleep(2000);
System.out.println(LocalTime.now());
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("数据=" +data.getResult() + " " +LocalTime.now());
}
}
二、FutureTask应用场景和源码解析
FutureTask使用场景上面只是大致说了一下,下面我们来举一个具体的场景:API网关。
比方说用户打开一个订单页面:可能要查许多接口:订单信息,积分信息,退换货信息,这时候如果串行去查这么多东西,很费时间。
这些信息是没有必要的先后关系的,所以可以做出并行的。平时我们用软件也能注意到,先出来这块信息,再出来那块信息,这就是并行去查的结果,当然也可以等所有信息都拿到,再同时返回。
FutureTask源码解析: