一、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. 请求发送成功!
  2. 做其它的事情......
  3. 根据请求参数进行查询,这是一个很耗时间的操作......
  4. 操作完毕,获取结果
  5. 查询结果

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

  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. }

并发模型之Future设计模式的更多相关文章

  1. 并发模型之Master-Worker设计模式

    一.Master-Worker设计模式 Master-Worker模式是常用的并行设计模式.它的核心思想是,系统有两个进程协议工作:Master进程和Worker进程.Master进程负责接收和分配任 ...

  2. 构建自己的Java并发模型框架

    Java的多线程特性为构建高性能的应用提供了极大的方便,可是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题须要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误. 另外.应用逻辑和线程逻辑 ...

  3. 构建Java并发模型框架

    Java的多线程特性为构建高性能的应用提供了极大的方便,但是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题需要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误.另外,应用逻辑和线程逻辑纠 ...

  4. 【并发编程】Future和FutureTask以及CompletionService

    Future接口 此接口主要用于: 代表异步计算的执行结果: 用于可取消的task:(比使用interrupt实现取消要方便 ) FutureTask类 FutureTask是Future的一个实现类 ...

  5. memcached源码剖析4:并发模型

    memcached是一个典型的单进程系统.虽然是单进程,但是memcached内部通过多线程实现了master-worker模型,这也是服务端最常见的一种并发模型.实际上,除了master线程和wor ...

  6. 【并发编程】Future模式添加Callback及Promise 模式

    Future Future是Java5增加的类,它用来描述一个异步计算的结果.你可以使用 isDone 方法检查计算是否完成,或者使用 get 方法阻塞住调用线程,直到计算完成返回结果.你也可以使用  ...

  7. Java并发模型框架

    构建Java并发模型框架 Java的多线程特性为构建高性能的应用提供了极大的方便,但是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题需要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误. ...

  8. 并发模型与IO模型梳理

    并发模型 常见的并发模型一般包括3类,基于线程与锁的内存共享模型,actor模型和CSP模型,其中尤以线程与锁的共享内存模型最为常见.由于go语言的兴起,CSP模型也越来越受关注.基于锁的共享内存模型 ...

  9. 课堂笔记--Strom并发模型

    Strom并发模型:     topology是如何运行的?(可与mapreduce对比)         第一层:cluster         第二层:supervisor(host.node.机 ...

随机推荐

  1. PHP一句话木马Webshell变形免杀总结

    0×00 前言 大部分Webshell查杀工具都是基于关键字特征的,通常他们会维护一个关键字列表,以此遍历指定扩展名的文件来进行扫描,所以可能最先想到的是各种字符串变形,下面总结了一些小的方法,各种不 ...

  2. 【Qt】Qt在Windows下的开发与调试环境配置

    前文已经交待了从源码编译Qt自定义版本.现在可以开始配置一下开发与调试程序并写个Hello World了. 1. IDE 虽然Qt官方有VS插件使我们可以在VisualStudio中开发Qt应用,但我 ...

  3. QuantLib 金融计算——基本组件之天数计算规则详解

    目录 天数计算规则详解 定义 30 / 360 法 30/360 US 30/360 Bond Basis 30E/360 30E/360 ISDA Actual 法 Actual/Actual IC ...

  4. Machine learning 第5周编程作业

    1.Sigmoid Gradient function g = sigmoidGradient(z) %SIGMOIDGRADIENT returns the gradient of the sigm ...

  5. CentOS 7 安装方式汇总

    U盘安装 通过U盘安装 CentOS 的过程和安装Windows非常相似,首先将 CentOS 镜像文件刻录到U盘(或者光盘),设置固件(BIOS或者UEFI)从U盘启动,然后逐步设置即可. 使用 V ...

  6. python学习,day3:函数式编程,递归和高阶函数

    # coding=utf-8 # Author: RyAn Bi def calc(n): #递归 print(n) if int(n/2) > 0: #设置条件,否则会循环999 次,报错, ...

  7. 1.CentOS6.5下的基础DNS配置

    常规DNS的安全和配置1.安装DNSyum -y install bind bind-utils安装后生成的文件,我们主要配置下面几个/etc/named.conf/var/named/xx这个xx是 ...

  8. 求幂大法,矩阵快速幂,快速幂模板题--hdu4549

    hdu-4549 求幂大法.矩阵快速幂.快速幂 题目 M斐波那契数列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 ...

  9. redis 常用的server的命令

  10. rocksDB vs InnoDB vsTokuDB

    原文地址 https://minervadb.com/index.php/2018/08/06/comparing-tokudb-rocksdb-and-innodb-performance-on-i ...