Fork me on GitHub

Future 模式简介

简介

Future 模式是多线程开发中的一种常见设计模式,它的核心思想是异步调用。

比如我们在网上购物,付款后就会产生一个订单,之后你该干嘛干嘛,快递小哥会上门送货,而不必像在超市结账那样,付款后要等着收银员打出小票再帮你打包商品,这个时间你只能站那等着。

总的来说,Future 模式无法立即给出你想要的结果,但它会给你一个契约,之后你可以随时通过这个契约来获取你想要的结果。

例子

下边举个简单的例子:

例子中,Data 接口有两个实现类,RealData 表示真实的数据也就是最终想要的,FutureData 表示一个契约,通过这个 FutureData 可以获得 RealData 的真实数据。

FutureData:

 1 package com.zhengbin.springboot.future;
 2 
 3 /**
 4  * Created by zhengbin on 2017/11/14
 5  */
 6 public class FutureData implements Data {
 7     private RealData realData = null;
 8     private boolean isReady = false;
 9 
10     public synchronized void setRealData(RealData realData) {
11         if (isReady) {
12             return;
13         }
14         this.realData = realData;
15         isReady = true;
16         notifyAll();
17     }
18 
19     @Override
20     public synchronized String getResult() {
21         while (!isReady) {
22             try {
23                 wait();
24             } catch (InterruptedException e) {
25             }
26         }
27         return realData.getResult();
28     }
29 }

FutureData 相当于 RealData 的代理(契约),封装了获取 RealData 等待的过程。

调用 getRealData 方法时,如果数据还没有准备好,线程就会等待(阻塞),当执行 setRealData 后,将会唤醒所有等待(阻塞)中的线程,这时才能获取到数据。

RealData:

 1 package com.zhengbin.springboot.future;
 2 
 3 /**
 4  * Created by zhengbin on 2017/11/14
 5  */
 6 public class RealData {
 7     private final String result;
 8 
 9     public RealData(String param) {
10         StringBuffer sb = new StringBuffer();
11         for (int i = 0;i < 10;i++) {
12             sb.append(param);
13             try {
14                 Thread.sleep(300);
15             } catch (InterruptedException e) {
16             }
17         }
18         result = sb.toString();
19     }
20 
21     public String getResult() {
22         return result;
23     }
24 }

RealData 的构造函数,模拟了一个数据构成很慢的过程。

Client:

 1 package com.zhengbin.springboot.future;
 2 
 3 /**
 4  * Created by zhengbin on 2017/11/14
 5  */
 6 public class Client {
 7     public Data request(final String requestStr) {
 8         final FutureData futureData = new FutureData();
 9         new Thread() {
10             @Override
11             public void run() {
12                 RealData realData = new RealData(requestStr);
13                 futureData.setRealData(realData);
14             }
15         }.start();
16         return futureData;
17     }
18 }

Client 就是我们调用的客户端,实现了获取 FutureData,并开启构造 RealData 的线程,该线程单独执行,主线程直接返回,只不过返回的是一个契约也就是 FutureData,真正的数据 RealData 则在另一个单独的线程中缓慢的构造,构造完成后就会通过 FutureData 的 setRealData 将真实数据保存,这样客户端就可以 get 到真实数据了。

FutureTest:

 1 package com.zhengbin.springboot.future;
 2 
 3 /**
 4  * Created by zhengbin on 2017/11/14
 5  */
 6 public class FutureTest {
 7     public static void main(String[] args) throws InterruptedException {
 8         Client client = new Client();
 9         Data futureData = client.request("zhengbin");
10         System.out.println("request done...");
11         Thread.sleep(500);
12         System.out.println("other done...");
13         System.out.println("result : "+futureData.getResult());
14     }
15 }

测试方法通过 Client 发起调用,调用后模拟执行其他的逻辑,耗费 0.5 秒,之后需要用到 Data 的数据了,但构造真实数据的时间需要 3 秒,此时主线程就会阻塞在这里,等待真实数据的构造完成。

这种方式就给了主线程去执行其他任务的时间,节省了 0.5 秒的时间,可以用来去做别的事情。

参考资料

[1] 实战 Java 高并发程序设计 5.5

posted @ 2018-01-21 16:24  郑斌blog  阅读(623)  评论(0编辑  收藏  举报