Future系列文章
Future三重奏第一章:Future設計模式及代碼示例
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的使用作出詳細介紹