Java併發模式—Future模式
阿新 • • 發佈:2019-02-06
Future
Future模式是多執行緒開發中非常常見的一種設計模式,它的核心思想是非同步呼叫。當我們需要呼叫一個函式方法時,如果這個函式執行很慢,那麼我們就要進行等待。但有時候,我們可能不急著要結果。因此,我們可以讓被調者立即返回,讓它在後臺慢慢處理這個請求。對於呼叫者來說,則可以先處理一些其他任務,在真正需要資料的場合再去嘗試獲得需要的資料。
對於Future模式來說,雖然它無法立即給出你需要的資料。但是,它會返回給你一個契約,將來,你可以憑藉這個契約去重新獲取你需要的資訊。
Future的簡易實現
參與者 | 作用 |
---|---|
Main | 系統啟動,呼叫Client發出請求 |
Client | 返回Data物件,立即返回FutureData,並開啟ClientThread執行緒裝配RealData |
Data | 返回資料的介面 |
FutureData | Future資料,構造很快,但是是一個虛擬的過程,需要裝配RealData |
RealData | 真實資料,其構造是比較慢的 |
下面是data介面
public interface Data {
public String getResult();
}
FutureData:
public class FutureData implements Data{
protected RealData realData = null;
protected boolean isReady = false;
public synchronized void setRealData(RealData realData){
if(isReady){
return;
}
this.realData = realData;
isReady = true;
notifyAll();
}
@Override
public synchronized String getResult() {
while (!isReady){
try{
wait();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
return realData.result;
}
}
RealData
public class RealData implements Data{
protected final String result;
public RealData(String para){
//RealData的構造可能很慢,需要使用者等待很久,這裡用seelp模擬
StringBuffer sb = new StringBuffer();
for(int i = 0; i < 10; i++){
sb.append(para);
}
try{
//這裡用sleep,代替一個很慢的操作過程
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
result = sb.toString();
}
@Override
public String getResult() {
return result;
}
}
Client類:
public class Client {
public Data request(final String queryStr){
final FutureData future = new FutureData();
new Thread(){
public void run(){ //RealData的構建很慢,所以在單獨執行緒中進行
RealData realData = new RealData(queryStr);
future.setRealData(realData);
}
}.start();
return future;
}
}
Main函式
public class Main {
public static void main(String[] args){
Client client = new Client();
//這裡會立即返回,因為得到的是FutureData而不是RealData
Data data= client.request("name");
System.out.println("請求完畢");
try{
//這裡可以用一個sleep代替了對其他業務邏輯的處理
//在處理這些業務邏輯的過程中,RealData被建立,從而充分利用了等待時間
Thread.sleep(2000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("資料= " + data.getResult());
}
}
JDK中的Future模式
可以通過Future介面來得到真實的資料。RunnableFuture繼承了Future和Ruuable介面,其中run()方法用於構造真實的資料。它有一個具體的實現FutureTask類。FutureTask有一個內部類Sync,一些實質性的工作,會委託Sync類實現。而Sync類最終會呼叫Callable介面,完成實際資料的組裝工作。
具體使用
RealData
package JDKFuture;
import java.util.concurrent.Callable;
public class RealData implements Callable<String> {
private String para;
public RealData(String para){
this.para = para;
}
@Override
public String call() throws Exception{
StringBuffer sb = new StringBuffer();
for(int i = 0 ; i < 10; i++){
sb.append(para);
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
return sb.toString();
}
}
FutureMain
package JDKFuture;
import org.omg.Messaging.SYNC_WITH_TRANSPORT;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public class FutureMain {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//構造FutureTask
FutureTask<String> future = new FutureTask<String>(new RealData("a"));
ExecutorService executor = Executors.newFixedThreadPool(1);
//執行FutureTask,相當與上例中的client.request("a")傳送請求
//在這裡開啟執行緒進行RealData的call()執行
executor.submit(future);
System.out.println("請求完畢");
try{
//這裡依然可以做額外操作,這裡使用sleep代替其他業務邏輯的處理
Thread.sleep(2000);
}catch (InterruptedException e){
e.printStackTrace();
}
//相當於data.getResult(),取得call()方法的返回值
//如果此時call()方法沒有執行完成,則依然會等待
System.out.println("資料 = " + future.get());
}
}
除了基本功能wait,JDK還為Future介面提供了一些簡單的控制功能。
boolean cancel(boolean mayInterruptIfRunning); //取消任務
boolean isCancelled(); //是否已經取消
boolean isDone(); //是否已完成
V get() throws InterruptedException,ExecutionException; //取得返回物件
V get(long timeout,TimeUnit unit) //取得返回物件,可以設定超時時間