zoukankan      html  css  js  c++  java
  • Future模式

    • Future模式简介

      Future模式有点类似于网上购物,在你购买商品,订单生效之后,你可以去做自己的事情,等待商家通过快递给你送货上门。Future模式就是,当某一程序提交请求,期望得到一个答复。但是可能服务器程序对这个请求的处理比较慢,因此不可能马上收到答复。但是,在传统的单线程环境下,调用函数是同步的,它必须等到服务程序返回结果,才能继续进行其他处理。而Future模式下,调用方法是异步的,原本等待返回的时间段,在主调函数中,则可以处理其他的任务。传统的串行程序钓友如下图所示:

      

      Future模式的处理流程:

      从图中可以看出,虽然call()本身是一个需要很长世间处理的程序。但是,服务程序不等数据处理完就立刻返回客户端一个伪数据(类似于商品订单,你购物需要的是商品本身),实现Future模式的客户端在拿到这个返回结果后,并不急于对它进行处理,而是去调用其它的业务逻辑,使call()方法有充分的时间去处理完成,这也是Future模式的精髓所在。在处理完其他业务逻辑后,最后再使用处理比较费时的Future数据。这个在处理过程中,就不存在无谓的等待,充分利用了时间,从而提升了系统的响应和性能。

    • Future模式的核心结构

      下面以一个经典的Future实现为例,简单介绍下Future的核心实现。代码中Date接口:返回数据的接口;FutureDate类:实现Date接口,构造很快,返回一个虚拟的伪数据,需要装配RealDate;RealDate类:实现Date接口,返回真实数据,构造比较慢;Client:返回Date数据,立即返回FutureDate数据,并开启线程装配RealDate数据。

      代码实现:

     1 public interface Data {
     2     public String getResult();
     3 }
     4 
     5 public class FutureData implements Data {
     6     
     7     protected RealData realData = null;
     8     
     9     protected boolean isReady = false;
    10     //进行同步控制
    11     public synchronized void setResult(RealData realData){
    12         if(isReady){
    13             return;
    14         }
    15         System.out.println("FutureData.setResult()");
    16         this.realData=realData;
    17         isReady = true;
    18         notifyAll();
    19         
    20     } 
    21     //实际调用返回RealDate的数据
    22     @Override
    23     public synchronized String getResult() {
    24         while(!isReady){
    25             try {
    26                 wait();
    27             } catch (InterruptedException e) {
    28                 e.printStackTrace();
    29             }
    30         }
    31         System.out.println("FutureData.getResult()");
    32         return realData.result;
    33     }
    34 
    35 public class RealData implements Data{
    36     
    37     protected final String result;
    38     
    39     public RealData(String s) {
    40         StringBuffer sb = new StringBuffer();
    41         
    42         for (int i = 0; i < 10; i++) {
    43             sb.append(s);
    44             try {
    45                 //模拟构造时间比较长
    46                 Thread.sleep(1000);
    47             } catch (InterruptedException e) {
    48                 
    49             }
    50             
    51         }
    52         
    53         System.out.println("RealData.RealData()");
    54         result = sb.toString();
    55     }
    56 
    57 public class Client {
    58     public Data request(final String queryStr){
    59                 //返回伪数据
    60         final FutureData futureData = new FutureData();
    61                 //开启线程构造真实数据
    62         new Thread(){
    63             public void run(){
    64                 RealData realData = new RealData(queryStr);
    65                 futureData.setResult(realData);
    66             }
    67         }.start();
    68                 //返回伪数据,等待真实数据加载
    69         return futureData;
    70     }
    71 }    

      启动系统,调用Client发送请求:

    1 public class TestMain {
    2     public static void main(String[] args) {
    3         Data data = new Client().request("123456");
    4         System.out.println(data);
    5         System.out.println(data.getResult());
    6     }
    7 }

      可以看出,FutureDate是Future模式实现的关键,它实际是真实数据RealDate的代理,封装了获取RealDate的等待过程。

    • JDK内置实现

      在JDK的内置并发包中,就已经内置了一种Future的实现,提供了更加丰富的线程控制,其基本用意和核心理念与上面实现代码一致。

      在JDK中的Future模式中,最重要的是FutureTask类,它实现了Runnable接口,可以作为单独的线程运行。在其run()方法中,通过Sync内部类,调用Callable接口,并维护Callable接口的返回对象。当使用FutureTask.get()时,将返回Callable接口的返回对象。FutureTask还可以对任务本身进行其他控制操作。

      利用Callable接口实现上述例子相同的操作:

      RealDate类的实现:

     1 public class Real1Data implements Callable<String>{
     2     
     3     private String reaString;
     4     
     5     public Real1Data(String reaString) {
     6         super();
     7         this.reaString = reaString;
     8     }
     9 
    10   
    11     @Override
    12     public String call() throws Exception {
    13         
    14         StringBuffer sb = new StringBuffer();
    15         
    16         for (int i = 0; i < 10; i++) {
    17             sb.append(reaString);
    18             try {
    19                 Thread.sleep(100);
    20             } catch (InterruptedException e) {
    21                 // TODO: handle exception
    22             }
    23             
    24         }
    25         
    26         return sb.toString();
    27     }
    28 
    29 }

      Client代码实现:

     1 public class Test1Main {
     2     public static void main(String[] args) throws InterruptedException, ExecutionException {
     3         FutureTask<String> future =  new FutureTask<>(new Real1Data("1111"));
     4         
     5         ExecutorService exe = Executors.newFixedThreadPool(1);
     6         
     7         exe.submit(future);
     8         
     9         System.out.println("FutureTask");
    10         
    11         try {
    12             Thread.sleep(1000);
    13         } catch (InterruptedException e) {
    14             // TODO Auto-generated catch block
    15             e.printStackTrace();
    16         }
    17         
    18         System.out.println("FutureTask"+future.get());
    19     }
    20 }    

      可以看出RealDate的构造速度很快,其核心代码逻辑放在了call()中实现,不再需要Date和FutureDate,直接通过RealDate来构造FutureTask,将其作为单独的线程运行。在提交请求后,执行其他业务逻辑,做好通过FututeTask.get()方法,得到RealDate的执行结果。

      Futute模式核心在于去除了主调用函数的等待时间,并使得原本需要等待的时间可以充分利用来处理其他业务逻辑,充分的利用了系统资源。

  • 相关阅读:
    MySQL 可重复读,差点就让我背上了一个 P0 事故
    Thread.sleep(0) 有什么用
    你不会还在用这8个错误的SQL写法吧?
    Spring事务失效的 8 大原因
    我说 SELECT COUNT(*) 会造成全表扫描,面试官让我回去等通知
    这么写参数校验(Validator)就不会被劝退了
    HyperLedger Fabric 1.4 基础环境搭建(7)
    HyperLedger Fabric 1.4 简介(6.1)
    HyperLedger Fabric 1.4 关键技术(6.4)
    HyperLedger Fabric 1.4 交易流程(6.3)
  • 原文地址:https://www.cnblogs.com/lcngu/p/5289605.html
Copyright © 2011-2022 走看看