简介
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