• 并发模型之Future设计模式


    一、Futrue模式

    客户端发送一个长时间的请求,服务端不需等待该数据处理完成便立即返回一个伪造的代理数据(相当于商品订单,不是商品本身),用户也无需等待,先去执行其他的若干操作后,再去调用服务器已经完成组装的真实数据。

    该模型充分利用了等待的时间片段。简单来说就是,如果线程A要等待线程B的结果,那么线程A没必要等待B,直到B有结果,可以先拿到一个未来的Future,等B有结果是再取真实的结果。

    在多线程中经常举的一个例子就是:网络图片的下载,刚开始是通过模糊的图片来代替最后的图片,等下载图片的线程下载完图片后在替换。而在这个过程中可以做一些其他的事情。

    二、Future模式的代码实现

    1、创建公共数据接口

     1 package com.ietree.basicskill.mutilthread.designpattern;
     2 
     3 /**
     4  * Created by Root on 5/12/2017.
     5  */
     6 public interface Data {
     7 
     8     String getRequest();
     9 
    10 }

    2、创建FutureData对象,当有程序想要获取RealData的时候,程序会被阻塞,等到RealData被注入才会使用getReal()方法

     1 package com.ietree.basicskill.mutilthread.designpattern;
     2 
     3 /**
     4  * Created by Root on 5/12/2017.
     5  */
     6 public class FutureData implements Data {
     7 
     8     private RealData realData;
     9 
    10     private boolean isReady = false;
    11 
    12     public synchronized void setRealData(RealData realData) {
    13         // 如果已经装载完毕了,就直接返回
    14         if (isReady) {
    15             return;
    16         }
    17         // 如果没装载,进行装载真实对象
    18         this.realData = realData;
    19         isReady = true;
    20         // 进行通知
    21         notify();
    22     }
    23 
    24     @Override
    25     public synchronized String getRequest() {
    26         // 如果没装载好,程序就一直处于阻塞状态
    27         while (!isReady) {
    28             try {
    29                 wait();
    30             } catch (InterruptedException e) {
    31                 e.printStackTrace();
    32             }
    33         }
    34         // 装载好了直接获取数据即可
    35         return this.realData.getRequest();
    36     }
    37 }

    3、真实数据RealData类

     1 package com.ietree.basicskill.mutilthread.designpattern;
     2 
     3 /**
     4  * Created by Root on 5/12/2017.
     5  */
     6 public class RealData implements Data {
     7 
     8     private String result;
     9 
    10     public RealData(String queryStr) {
    11         System.out.println("根据" + queryStr + "进行查询,这是一个很耗时间的操作......");
    12         try {
    13             Thread.sleep(5000);
    14         } catch (InterruptedException e) {
    15             e.printStackTrace();
    16         }
    17         System.out.println("操作完毕,获取结果");
    18         result = "查询结果";
    19     }
    20 
    21     @Override
    22     public String getRequest() {
    23         return result;
    24     }
    25 }

    4、客户端代理类

     1 package com.ietree.basicskill.mutilthread.designpattern;
     2 
     3 /**
     4  * Created by Root on 5/12/2017.
     5  */
     6 public class FutureClient {
     7 
     8     public Data request(final String queryStr) {
     9         //1 我想要一个代理对象(Data接口的实现类)先返回给发送请求的客户端,告诉他请求已经接收到,可以做其他的事情
    10         final FutureData futureData = new FutureData();
    11         //2 启动一个新的线程,去加载真实的数据,传递给这个代理对象
    12         new Thread(new Runnable() {
    13             @Override
    14             public void run() {
    15                 //3 这个新的线程可以去慢慢的加载真实对象,然后传递给代理对象
    16                 RealData realData = new RealData(queryStr);
    17                 futureData.setRealData(realData);
    18             }
    19         }).start();
    20 
    21         return futureData;
    22     }
    23 
    24 }

    5、测试调用

     1 package com.ietree.basicskill.mutilthread.designpattern;
     2 
     3 /**
     4  * Created by Root on 5/12/2017.
     5  */
     6 public class FutureTest {
     7 
     8     public static void main(String[] args) {
     9         FutureClient fc = new FutureClient();
    10         Data data = fc.request("请求参数");
    11         System.out.println("请求发送成功!");
    12 
    13         try {
    14             //处理其他业务
    15             //这个过程中,真实数据RealData组装完成,重复利用等待时间
    16             System.out.println("做其它的事情......");
    17             Thread.sleep(2000);
    18         } catch (InterruptedException e) {
    19             e.printStackTrace();
    20         }
    21 
    22         // 获取真实数据
    23         String result = data.getRequest();
    24         System.out.println(result);
    25     }
    26 
    27 }

    程序运行结果:

    请求发送成功!
    做其它的事情......
    根据请求参数进行查询,这是一个很耗时间的操作......
    操作完毕,获取结果
    查询结果

    第二种写法(没有实际运用过):

     1 package com.ietree.basicskill.mutilthread.designpattern;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 import java.util.concurrent.Callable;
     6 import java.util.concurrent.ExecutionException;
     7 import java.util.concurrent.ExecutorService;
     8 import java.util.concurrent.Executors;
     9 import java.util.concurrent.Future;
    10 
    11 /**
    12  * Created by Root on 5/12/2017.
    13  */
    14 public class FutureTest2 {
    15 
    16     private static class Task implements Callable<String> {
    17         @Override
    18         public String call() throws Exception {
    19             // 模拟真实事务的处理过程,这个过程是非常耗时的。
    20             Thread.sleep(5000);
    21             return "call return ";
    22         }
    23     }
    24 
    25     public static void main(String[] args) throws InterruptedException, ExecutionException {
    26         
    27         List<Future<String>> futures = new ArrayList<Future<String>>();
    28         ExecutorService executorService = Executors.newCachedThreadPool();
    29 
    30         System.out.println("已经提交资源申请");
    31         for (int i = 0; i < 10; i++) {
    32             futures.add(executorService.submit(new Task()));
    33         }
    34 
    35         for (Future<String> future : futures) {
    36             // 判断资源是不是已经准备完毕,准备完毕直接获取。
    37             if (!future.isDone()) {
    38                 System.out.println("资源还没有准备好");
    39             }
    40             System.out.println(future.get());
    41         }
    42         executorService.shutdown();
    43     }
    44 }
  • 相关阅读:
    Python3网络学习案例三:编写web server
    struct.pack()和struct.unpack() 详解(转载)
    Python3网络学习案例二:traceroute详解
    Redis 配置
    vue之this.$route.params和this.$route.query的区别
    解决bugs: mybatisPlus 分页不能生效
    解决bug :"status":400,"error":"Bad Request","message":"Required request body is missing:
    vue,ElementUI中Switch 开关,switch 打开时的值为数字,该如何设置
    解决bug:vue项目中点击修改按钮,不能显示要修改的分类名字
    The 'Access-Control-Allow-Origin' header contains multiple values'*, *', but only one is allowed.
  • 原文地址:https://www.cnblogs.com/Dylansuns/p/6847623.html
Copyright © 2020-2023  润新知