傳統單線程環境下,調用函數是同步的,必須等待程序返回結果後,纔可進行其餘處理。 Futrue模式下,調用方式改成異步。java
Futrue模式的核心在於:充分利用主函數中的等待時間,利用等待時間處理其餘任務,充分利用計算機資源。異步
future模式有兩種數據, 一種是真實數據RealData, 裏面就是業務中想要獲得的目標數據. 另外一種是虛擬數據FutureData, 它是在使用future模式時當即返回的一個對象. ide
調用方會首先拿到一個FutureData, 而後調用方就認爲本身拿到該數據了, 沒有進行阻塞, 繼續去執行下面的邏輯處理. 若是真實數據準備好了, 就會把本身的引用賦給以前的那個FutureData, 而且置一個標記, 表示這個FutureData裏面包含一個RealData, 拿到了想要的數據, 可使用.函數
詳細分的話, 會有下面這幾種狀況(假設RealData須要2秒才能建立好):this
1. 調用方發送了本身須要RealData的請求的後, 會當即拿到一個FutureData, 可是根本就不着急使用, 因此, 第2秒的時候RealData建立完成後, 就會被綁定到對應的FutureData裏. 假設第6秒調用方纔開始使用RealData, 他會發現FutureData已經準保好了他想要的數據, 因而開心地使用就ok了.線程
2. 調用方發送了本身須要RealData的請求的後, 會當即拿到一個FutureData, 可是很着急使用, 由於接下來的處理過程依賴於RealData的內容. 因而在第0.5秒的時候, 調用方就想要獲取RealData. 可是這個時候RealData並無準備好, 此時的FutureData是一個空殼而已. 因此就在這裏進行wait(或者忙等待). 直到RealData準備好,也就是再過1.5秒, 線程纔會喚醒(或者打破忙等待).對象
public interface Data { int getResult() throws InterruptedException; }
public class RealData implements Data { private int data; public RealData(int num) { //這裏用sleep來模擬構造一個複雜對象的場景 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } this.data = num * 10; } @Override public int getResult() { return data; } }
public class FutureData implements Data { // 真實數據RealData的引用. private RealData realData = null; public synchronized void setRealData(RealData realData) { // 若是this.realData不是空, 說明已經準備好了, 直接return if (this.realData != null) return; this.realData = realData; notifyAll(); } @Override public synchronized int getResult() throws InterruptedException { // 若是this.realData是null, 說明數據還沒準備好, 應該等待 if (this.realData == null) { wait(); } return realData.getResult(); } }
直接建立一個FutureData, 而後直接返回這個FutureData. 同事開闢一個線程來建立RealData, 而且在RealData建立完後綁定在FutureData中.blog
public class Client { public Data request(final int num) { // 當有請求的時候, 先建立一個虛擬對象. final FutureData futureData = new FutureData(); // 而後開啓一個新線程去建立RealData, 當RealData建立完成後, 綁定帶FutureData裏. new Thread(() -> { RealData realData = new RealData(num); futureData.setRealData(realData); }).start(); // 無論RealData有沒有建立完成, 都會直接返回這個FutureData. return futureData; } }
調用這個Future模型.接口
public class Main { public static void main(String[] args) throws InterruptedException { Client client = new Client(); // 調用了以後會當即返回一個FutureData, 這個data就是FutureData Data data = client.request(4); // 用sleep來模擬主線程正在處理其餘事情 Thread.sleep(0); // getResult來獲取真實數據 // |- 若是這時候真實數據沒準備好, 那麼就wait, 等待notify, 而後獲取到真實數據 // |- 若是這時候真實數據準備好了, 那麼就能夠直接獲取到了 System.out.println("數據=" + data.getResult()); } }
在RealData處進行了*10 的處理, 因此request(4), 最終會返回40.資源
使用過, 例子以下:
import java.util.concurrent.Callable; public class RealData implements Callable<Integer> { private int data; public RealData(int data) { this.data = data * 10; } @Override public Integer call() { //利用sleep方法來表示真是業務是很是緩慢的 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return data; } }
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; public class Main { public static void main(String[] args) throws Exception { //線程池 ExecutorService executor = Executors.newFixedThreadPool(1); //使用線程池 // 以前本身實現的future模式中的 Data data = client.request(4) 這句至關於下面這兩行代碼 //1. Data data FutureTask<Integer> futureTask = new FutureTask<>(new RealData(4)); //2. 這裏至關於 client.request(4); executor.submit(futureTask); //這裏能夠用一個sleep代替對其餘業務邏輯的處理 Thread.sleep(0); // 獲取真實數據 try { System.out.println("數據=" + futureTask.get()); }finally { executor.shutdown(); } } }