Future系列文章
Future三重奏第一章:Future设计模式及代码示例
Future三重奏第二章:FutureTask源码解析
Future三重奏第三章:FutureTask中一些知识点的总结与补充
Future模式的作用
去除等待主函数执行某项耗时操作的等待时间,在执行主函数耗时业务操作的时候,及时返回一个数据,继续主函数剩下的业务,当需要获取之前耗时操作的结果的时候在进行获取
其本质则是在维持主业务顺利进行的同时,异步的执行主业务中的耗时分业务,使得原本需要进行等待的时间可以处理其他的业务
实际业务场景:
在开具电子发票的业务中,当我们申请开电子发票的时候,电子发票并不会立即开票成功,而是需要调取第三方接口,第三方接口在返回告诉我们是否开具成功,这时候需要等待一段时间才能得到开票结果,在等待第三方返回结果的同时,这个时候我们还有其他别的业务要进行处理返回,不可能一直等待第三方返回的数据,这时候我们就可以采用future模式,将该方法改为异步处理,在等待数据返回的时候进行其他业务的处理
future模式核心类作用
此处通过几个简单的类来展示future模式的思路和运行方式
Main类:系统启动类,调用Client类发出业务请求
Client类:该类在接收到构造并返回FutureData类,返回的FutureData类是一个虚假的对象,或者说并不是一个拥有实际数据的对象,Client的核心在于构建一个新的线程去执行RealData类,该类是处理耗时的业务类
Data:获取实际数据的接口,futureData类和realData类需要实现该接口
FutureData类:及时返回调用类,内部封装了实际数据,可通过该类获取实际的业务数据
RealData:实际的业务处理类,耗时较长
future模式示例代码
Main类
发起请求,构建执行了Client类,返回了Data对象,并在最后调用了data对象实际获取到的数据
public class Main {
public static void main(String args[]){
Client client=new Client();
//调用client发送请求
Data data=client.request("Hello Future!");
System.out.println("请求完毕!");
try {
//模拟处理其他业务
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//调用实际返回的数据
System.out.println("真实数据:" + data.getResult());
}
}
Data接口
Main类中实际返回Data对象,该接口提供获取数据的方法
public interface Data {
String getResult();
}
Client类
在主类中构建的Client类,并返回futureData对象,另一方面通过该类生成线程发出异步请求,新线程中执行业务类,并返回计算结果,将计算结果封装进futureData对象中
public class Client {
public Data request(String param){
//立即返回futureData
FutureData futureData=new FutureData();
//需要启动一个新线程
//开启ClientThread线程装配realData
new Thread(() -> {
//装配realData
//RealData为业务类,传递相关参数过去
RealData realData=new RealData(param);
//获取到数据后将数据封装进实体类中
futureData.setRealData(realData);
}).start();
return futureData;
}
}
RealData类
实际业务类,该类主要是执行业务方法并得到计算结果,并提供获取数据的方法
public class RealData implements Data{
private String result;//封装实际数据
/**
* 获取计算结果方法
* @return
*/
@Override
public String getResult() {
return result;
}
public RealData(String param){
StringBuffer sb=new StringBuffer();
sb.append(param);
//模拟业务执行
//此处通过线程睡眠的方式
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取真实数据result,等待再次获取数据
result=sb.toString();
}
}
FutureData类
在client的调用中,会首先返回一个空的futuredata对象,然后启动一个新的线程去执行业务类获取数据,在获取数据后,会将获取的数据封装进futuredata类中,所以,futuredata类相应的提供了封装实际数据的方法。当你需要获取实际数据当时候,如果尚未获取数据成功,则进入等待队列
public class FutureData implements Data {
private RealData realData;
private boolean isReady=false;//如果已经获取数据此处为true
private ReentrantLock lock=new ReentrantLock();
private Condition condition=lock.newCondition();
/**
* 获取实际数据
* @return
*/
@Override
public String getResult()
{
//如果尚未成功获取数据,则当前线程加入等待队列
while (!isReady){
try {
lock.lock();
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
return realData.getResult();
}
public void setRealData(RealData realData){
lock.lock();
if (isReady){
return;
}
//装载实际数据对象
this.realData = realData;
isReady = true;
condition.signal();
lock.unlock();
}
}
以上就是future设计模式的简单实现,future模式在线程池的实现中有很大的体现,在第二章中我会详细介绍jdk中futuretask的详细实现,在线程池模块中也会对futureTask的使用作出详细介绍
- 如果喜欢我的文章,可以随手点一下文末的喜欢
- 技术理解不到或有错误请直(bu)接(yao)指(ma)出(wo)
- 写作不易!