標籤:state 主函數 調用 call() 之間 param blog str 方式
Java多線程Future模式有些類似於Ajax的非同步請求
Future模式的核心在於:去除了主函數的等待時間,並使得原本需要等待的時間段可以用於處理其他商務邏輯
假設伺服器的處理某個業務,該業務可以分成AB兩個過程,並且AB兩個過程之間不需要彼此的返回結果A過程需要1秒鐘,B過程需要2秒鐘,主線程其他動作2秒鐘
按照正常編寫,程式大概需要執行5秒
如果按照Future模式只需要執行2秒(取其中已耗用時間最久的線程的已耗用時間)
Future模式的核心實現在於兩個方面
1.多線程運行
主線程採用多線的方式,運行幾個業務無關的任務來節省主線的等待時間。
2.鎖的鎖定和釋放
子線程執行指定的任務時,需要保證主線程能正確的擷取子線程的返回資料
這裡分兩種情況
(1)子線程的已耗用時間要大於主線程處理其他業務的時間,此時主線程需要擷取子線程的傳回值,而子線程卻還沒有執行完畢,
所以在這個時候需要讓主線程進入等待。子線程執行完畢以後立刻喚醒主線程。
(2)子線程的已耗用時間小於主線處理其他業務的時間,此時無需要等待。
知識要點:
1、wait(),notify()需要和synchronized一塊使用,去掉會報 java.lang.IllegalMonitorStateException
1>當前線程不含有當前對象的鎖資源的時候,調用obj.wait()方法;
2>當前線程不含有當前對象的鎖資源的時候,調用obj.notify()方法。
3>當前線程不含有當前對象的鎖資源的時候,調用obj.notifyAll()方法。
2、wait()方法會釋放鎖
Service類比伺服器處理業務的過程
package future;import java.util.Date;/** * 伺服器 * * @author wpy * */public class Service {/** * 1.伺服器的處理某個業務,該業務可以分成AB兩個過程,並且AB兩個過程之間不需要彼此的返回結果 * 2.A過程需要1秒鐘,B過程需要2秒鐘,主線程其他動作2秒鐘 * * @param args * @throws InterruptedException */public static void main(String[] args) throws InterruptedException {Service service = new Service();long notUseFuture = service.notUseFuture();System.out.println("==============================");long useFuture = service.useFuture();System.out.println("==============================");System.out.println("notUseFuture整個業務耗時"+notUseFuture);System.out.println("useFuture整個業務耗時"+useFuture);}public long useFuture() throws InterruptedException {Date startOn = new Date();String name = Thread.currentThread().getName();final FutureDate<String> futureDateA = new FutureDate<>();final FutureDate<String> futureDateB = new FutureDate<>();Thread a = new Thread(new Runnable() {@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name + ":任務A開始執行");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}futureDateA.setData(name + ":任務A執行結果");System.out.println(name + ":任務A執行結束");}}, "線程A");Thread b = new Thread(new Runnable() {@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name + ":任務B開始執行");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}futureDateB.setData(name + ":任務B執行結果");System.out.println(name + ":任務B執行結束");}}, "線程B");Date before = new Date();a.start();b.start();Date after = new Date();System.out.println(name + ":a,b阻塞主線程時間:"+ (after.getTime() - before.getTime()));// 假設其他業務執行兩秒鐘Thread.sleep(2000);before = new Date();String dataA = futureDateA.getData();after = new Date();System.out.println(name + ":擷取A線程結果時間:"+ (after.getTime() - before.getTime()));before = new Date();String dataB = futureDateB.getData();after = new Date();System.out.println(name + ":擷取線程結果時間:"+ (after.getTime() - before.getTime()));System.out.println(name + ":A線程結果:" + dataA);System.out.println(name + ":B線程結果:" + dataB);Date endOn = new Date();/*System.out.println(name + "整個業務耗時"+ (endOn.getTime() - startOn.getTime()));*/return endOn.getTime() - startOn.getTime();}public long notUseFuture() throws InterruptedException {Date startOn = new Date();// 任務AString name = Thread.currentThread().getName();System.out.println(name + ":任務A開始執行");Thread.sleep(1000);System.out.println(name + ":任務A執行結束");// 任務BSystem.out.println(name + ":任務B開始執行");Thread.sleep(3000);System.out.println(name + ":任務B執行結束");// 主線程其他動作Thread.sleep(2000);Date endOn = new Date();return endOn.getTime() - startOn.getTime();}}
封裝的FutrueData類
package future;/** * 使用者擷取非同步任務執行結果 * @author wpy * */public class FutureDate<T> {private boolean isReady = false;private T data;/** * 非同步任務執行完畢後會通過此方法將執行結果傳遞給data; * @param data */public synchronized void setData(T data){if(isReady){return;}this.data = data;isReady = true;notify();}/** * 如果資料沒有載入完畢,線程積蓄等待 * wait()會釋放鎖 * @return * @throws InterruptedException */public synchronized T getData() throws InterruptedException{if(!isReady){wait();}return data;}}
執行結果
main:任務A開始執行main:任務A執行結束main:任務B開始執行main:任務B執行結束==============================main:a,b阻塞主線程時間:0線程A:任務A開始執行線程B:任務B開始執行線程A:任務A執行結束main:擷取A線程結果時間:0線程B:任務B執行結束main:擷取線程結果時間:1001main:A線程結果:線程A:任務A執行結果main:B線程結果:線程B:任務B執行結果==============================notUseFuture整個業務耗時6001useFuture整個業務耗時3006
JDK封裝的Future簡單使用
package test;import java.util.Date;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class TestFuture {public static void main(String[] args) throws InterruptedException, ExecutionException {Callable<Object> callable = new Callable<Object>() {@Overridepublic Object call() throws Exception {System.out.println(Thread.currentThread().getName()+":正在構造資料");Thread.sleep(1000);System.out.println(Thread.currentThread().getName()+":構造資料資料完畢");return "結果";}};Date before = new Date();FutureTask<Object> futureTask = new FutureTask<>(callable);new Thread(futureTask).start();Thread.sleep(1000);Date after = new Date();System.out.println((after.getTime() - before.getTime())/1000);before = new Date();System.out.println(Thread.currentThread().getName()+":主程式準備擷取結果");Object object = futureTask.get();after = new Date();System.out.println((after.getTime() - before.getTime())/1000);System.out.println(object);}}
Java多線程Future模式