1. 程式人生 > >13.多執行緒設計模式 - Future模式

13.多執行緒設計模式 - Future模式

多執行緒設計模式 - Future模式

併發設計模式屬於設計優化的一部分,它對於一些常用的多執行緒結構的總結和抽象。與序列相比並行程式結構通常較為複雜,因此合理的使用並行模式在多執行緒併發中更具有意義。

1. Future

 

Future模式是多執行緒開發中非常常見的一種設計模式,它的核心思想是非同步呼叫。

這類似我們日常生活中的線上購物流程,帶在購物網看著一件商品時可以提交表單,當訂單完成後就可以在家裡等待商品送貨上門。

或者說更形象的是我們傳送Ajax請求的時候,頁面是非同步的進行後臺處理,使用者無需等待請求的結果,可以繼續瀏覽或操作其他內容

示例:下面示例為Future的原理實現;<br />
說明:看類註釋即可明瞭 不明白可以去屎

 

 1 //Data.java   * 首先看這個介面Data,只有一個方法getRequest(),返回String字串.
 2   public interface Data {
 3       String getRequest();
 4   }
 5   //RealData.java   * 然後再看RealData這個類,實現了Data介面,首先他有建構函式,可以理解為一個真實的業務邏輯,比較耗時,做這個sleep我們可以想象成在處理業務邏輯.
 6   public class RealData implements Data{
 7       private
String result; 8 9 public RealData(String queryStr){ 10 System.out.println("根據"+queryStr+"進行查詢,這是一個很耗時的操作.."); 11 try { 12 Thread.sleep(5000); 13 } catch (InterruptedException e) { 14 e.printStackTrace(); 15 } 16 System.out.println("操作完畢,獲取結果");
17 result="查詢結果"; 18 } 19 20 @Override 21 public String getRequest() { 22 return result; 23 } 24 } 25 26 //FutureData.java* 接著再看FutureData這個類,也實現了Data介面.先看FutureData的getRequest()方法,這個方法先死迴圈判斷boolean,如果isReady是true,就阻塞著,不然就返回RealData真的getRequest()\\\方法(真實的結果). 27 // 然後再看setRealData(),判斷isReady,如果是ture,直接return,如果不是就賦值RealData,並修改isReady,然後notify().. 28 public class FutureData implements Data{ 29 30 private RealData realData; 31 private boolean isReady = false; 32 33 public synchronized void setRealData(RealData realData){ 34 //如果已經載入完畢就直接返回 35 if(isReady){ 36 return; 37 } 38 //如果沒有裝載,進行裝載真實物件 39 this.realData= realData; 40 isReady = true; 41 //進行通知 42 notify(); 43 } 44 45 @Override 46 public synchronized String getRequest() { 47 //如果沒有裝載好,程式就一直處於阻塞狀態 48 while(!isReady){ 49 try { 50 wait(); 51 } catch (InterruptedException e) { 52 e.printStackTrace(); 53 } 54 } 55 //裝載好直接獲取資料即可 56 return this.realData.getRequest(); 57 } 58 } 59 //FutureClient.java * 最後看FutureClient 這個類,最簡單了,返回futureData,偷偷開了執行緒,看到RealData realData = new RealData(request)沒有?就是開始執行業務了,然後當FutureData這個類的setRealData(RealData realData)時就通知了.. 60 public class FutureClient { 61 62 public Data request(final String queryStr){ 63 //1 我想要一個代理物件(Data介面的實現類)先返回傳送請求的客戶端,告訴他請求已經接收到,可以做其他事情 64 final FutureData futureData = new FutureData(); 65 //2 啟動一個新的執行緒,去載入真實的資料,傳遞給這個代理物件 66 new Thread(new Runnable(){ 67 @Override 68 public void run() { 69 //3 這個新的執行緒可以去慢慢載入真實物件,然後傳遞給代理物件 70 RealData realData = new RealData(queryStr); 71 futureData.setRealData(realData); 72 } 73 }).start(); 74 //直接返回一個假的包裝類futureData 75 return futureData; 76 } 77 } 78 //主函式 79 public class Main { 80 81 public static void main(String[] args) { 82 FutureClient fc = new FutureClient(); 83 Data data = fc.request("請求引數"); 84 System.out.println("請求傳送成功!"); 85 System.out.println("做其他的事情..."); 86 87 String result = data.getRequest(); 88 System.out.println(result); 89 } 90 }

上面的原理你可以不用懂,當然懂最好了,可以在面試官面前吹牛逼啊..future模式這麼凶殘,jdk也有實現的,在java.util.concurrent,又是concurrent,這個工具類真的是強大<br />
示例:<br />

 1 //
 2   import java.util.concurrent.Callable;
 3 
 4   public class RealData implements Callable<String> {
 5     private String Data;
 6 
 7     public RealData(String Data) {
 8         this.Data = Data;
 9     }
10 
11     public String call() throws Exception {
12         //利用sleep來表示任務處理
13         Thread.sleep(2000);
14 
15         return "這是處理"+Data+"結果";
16     }
17   }
18   //
19   import java.util.concurrent.ExecutorService;
20   import java.util.concurrent.Executors;
21   import java.util.concurrent.FutureTask;
22 
23   public class Main {
24 
25       public static void main(String[] args) throws Exception {
26           Long start = System.currentTimeMillis();
27 
28           FutureTask<String> futureTask = new FutureTask<>(new RealData("hello,world"));
29           ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(1);
30           newFixedThreadPool.submit(futureTask);
31 
32           // 表示正在處理其他邏輯,或者業務
33           Thread.sleep(1000);
34 
35           System.out.println("最後結果-->" + futureTask.get());
36 
37           Long end = System.currentTimeMillis();
38 
39           Long useTime = end - start;
40 
41           System.out.println("程式運行了-->" + useTime + "毫秒");
42       }
43   }