1.Future模式

Future模式和多线程技术密切相关,可以说是利用多线程技术优化程序的一个实例。

在程序设计中,当某一段程序提交了一个请求,期望得到一个答复。但非常不幸的是,服务程序对这个请求的处理可能比较慢,比如,这个请求可能是通过互联网、HTTP或者Web Service等并不高效的方式调用的。在传统的单线程环境下,调用函数是同步的,也就是说它必须等到服务程序返回结束后,才能进行其他处理。而在Future模式下,调用方式改为异步的,而原先等待返回的时间段,在主调用函数中,则可能用于处理其它事务。下面我们尝试实现这一功能:

1)Main方法的实现

main方法主要负责调用Client发起请求,并使用返回的数据:

public class Future {
    public static void main(String[] args) {
        Client client = new Client();
        Data data = client.request("name");
        System.out.println("请求完毕 "+System.currentTimeMillis());
        //...这里做一些其它任务
        System.out.println("数据:"+data.getResult());
        System.out.println("获取完毕 "+System.currentTimeMillis());
    }
}

2)Client的实现

client主要实现了获取FutureData,开启构造RealData的线程,并在接受请求后,很快的返回FutureData。

public class Client {
    public Data request(String queryStr){
        FutureData futureData = new FutureData();
        new Thread(new Runnable() {
            @Override
            public void run() {
                RealData realData =  new RealData(queryStr);
                futureData.setRealData(realData);
            }
        }).start();
        return futureData;
    }
}

3)Data的实现

Data是一个接口,提供了getResult()方法。

public interface Data {
    String getResult();
}

4)FutureData的实现

FutureData 实现了一个快速返回的RealData 包装。它只是一个包装,或者说是一个RealData 的虚拟实现 。因此,它可以很快被构造并返回。当使用FutureData的getResult()方法时,程序会阻塞,等待RealData()被注入到程序中,才使用RealData的getResult()方法返回。

public class FutureData implements Data {
    private  RealData realData = null;
    private  boolean isReady = false;

    synchronized public void setRealData(RealData realData){
        if (isReady){
            return;
        }
        this.realData = realData;
        isReady = true;
        notifyAll(); //通知所有等待的线程继续运行
    }

    @Override
    synchronized public String getResult() {
        while (!isReady){
            try {
                System.out.print("...waiting...");
                wait(); //使当前线程在此处进行等待,直到被通知后继续运行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return realData.result;
    }
}

5)RealData 的实现

RealData 是最终需要使用的数据模型,它的构造很慢。在这里,使用sleep()函数模拟这个过程。

public class RealData implements Data {
    protected String result;

    public RealData(String para) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result = "["+para+"]";
    }

    @Override
    public String getResult() {
        return result;
    }
}

运行结果:

请求完毕 1537520554813
...waiting...
数据:[name]
获取完毕 1537520555890

程序运行的流程是Main线程去获取数据,但是数据还在处理中,于是Main线程进入等待状态,当数据处理完并通知等待所有等待的线程之后,Main线程得以继续运行下去。

2.JDK的内置实现

Future模式如此常用,以至于在JDK的并发包中,就已经内置了一种Future模式的实现了。

示例程序:

public class RealData implements Callable<String> {
    private String para;

    public RealData(String para) {
        this.para = para;
    }

    @Override
    public String call() throws Exception {
        //这里是真实的业务逻辑
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "["+para+"]";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //传入RealData到FutureTask
        FutureTask<String> futureTask = new FutureTask<String>(new RealData("name"));
        //创建一个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        //在这里开启线程执行RealData的call()方法
        executorService.submit(futureTask);
        System.out.println("请求完毕 "+System.currentTimeMillis());
        //...这里进行一些其它操作
        System.out.println("数据:"+futureTask.get());
        System.out.println("获取完毕 "+System.currentTimeMillis());
        //启动一个有序的关闭,之前提交的任务将被执行,但是不会接受新的任务。
        executorService.shutdown();
    }

}

运行结果:

请求完毕 1537521833970
数据:[name]
获取完毕 1537521834977

Callable接口是一个用户自定义实现的接口。在应用程序中,通过实现Callable接口的call()方法,指定FutureTask的实际内容和返回对象。

Future接口提供的线程控制功能有:

//取消任务
boolean cancel(boolean mayInterruptIfRunning)
//是否已经取消
boolean isCancelled()
//是否已经完成
boolean isDone()
//取得返回对象
V get() throws InterruptedException, ExecutionException
//取得返回对象,可以设置超时时间
V get(long timeout, TimeUnit unit)

尾声

Future模式的核心在于使用多线程技术去除了主函数中的等待时间,并使得原来需要等待的时间段可以用于处理其他的业务逻辑,从而充分利用计算机资源。

本文已授权微信公众号“后端技术精选”发布

深入理解[Future模式]原理与技术的更多相关文章

  1. 深入理解[Master-Worker模式]原理与技术

    Master-Worker模式是常用的并行模式之一.它的核心思想是,系统由两类进程协作工作:Master进程和Worker进程.Master进程负责接收和分配任务,Worker进程负责处理子任务.当各 ...

  2. 我理解的Future模式

    学而时习之,不亦说乎!                              --<论语> 什么是Future? 考虑一个场景,为了完成某个业务,我需要同时查询三张表的三条独立数据.但 ...

  3. Java中的Future模式原理自定义实现

    摘要:Future模式类似于js中的ajax等,是一个异步获取数据的机制,这里我把自己的一些形象理解通过代码实现了一下.该机制可以形象的理解为:调用获取数据的方法,首先获得一个没有装数据的空箱子(这个 ...

  4. 彻底理解Java的Future模式

    先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...

  5. 彻底理解Future模式

    先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...

  6. 13.多线程设计模式 - Future模式

    多线程设计模式 - Future模式 并发设计模式属于设计优化的一部分,它对于一些常用的多线程结构的总结和抽象.与串行相比并行程序结构通常较为复杂,因此合理的使用并行模式在多线程并发中更具有意义. 1 ...

  7. Java是如何实现Future模式的?万字详解!

    JDK1.8源码分析项目(中文注释)Github地址: https://github.com/yuanmabiji/jdk1.8-sourcecode-blogs 1 Future是什么? 先举个例子 ...

  8. titit. 深入理解 内聚( Cohesion)原理and  attilax大总结

    atitit. 深入理解 内聚( Cohesion)原理and  attilax大总结         1.1. 内聚的概念 1 1.1.1. 高内聚模式关于这个问题给出的答案是:分配职责,使其可保持 ...

  9. 深入理解OpenGL拾取模式(OpenGL Picking)

    深入理解OpenGL拾取模式(OpenGL Picking) 本文转自:http://blog.csdn.net/zhangci226/article/details/4749526 在用OpenGL ...

随机推荐

  1. 「Android」 Surface分析

    本篇针对Surface模块进行分析,从Java层的Activity创建开始,到ViewRoot.WindowsManagerService,再到JNI层和Native层. 首先推荐一个Android源 ...

  2. Centos 7下VMware三台虚拟机Hadoop集群初体验

    一.下载并安装Centos 7 传送门:https://www.centos.org/download/    注:下载DVD ISO镜像 这里详解一下VMware安装中的两个过程 网卡配置 是Add ...

  3. (后端)安装mongodb以及设置为windows服务 详细步骤(转)

    1.在data文件夹下新建一个log文件夹,用于存放日志文件,在log文件夹下新建文件mongodb.log 2.在 D:\mongodb文件夹下新建文件mongo.config,并用记事本打开mon ...

  4. 使用Visual Studio Team Services持续集成(二)——为构建定义属性

    使用Visual Studio Team Services持续集成(二)--为构建定义属性 1.从VSTS帐户进入到Build 2.编辑构建定义并单击Options Description:如果这里明 ...

  5. UITableView的分割线长短的控制

    UITableView的默认的cell的分割线左边没有顶满,而右边却顶满了.这样显示很难看.我需要让其左右两边都是未顶满状态,距离是20像素 // code1 if ([self.tableView ...

  6. Dos环境变量修改

    批处理修改环境变量,修改用户变量.系统变量(全局变量),永久/临时设置环境变量.设置Java环境变量 临时环境变量 修改变量: set PATH=%Path%;%JAVA_HOME%\bin 含义:表 ...

  7. 【算法】LeetCode算法题-Palindrome Number

    这是悦乐书的第144次更新,第146篇原创 今天这道题和回文有关,即从前往后和从后往前是一样的,如"上海自来水来自海上"就是一个回文字符串,如整数121就是回文数,这些都是和回文相 ...

  8. Linux 小知识翻译 - 「代理服务器」

    这回聊聊「代理服务器」. 在公司里,不通过代理服务器无法连接互联网的,由于代理服务器的原因,有些服务的使用是受到限制的. 有人可能会觉得为什么会存在这种东西?(这里指代理服务器) Proxy本来的意思 ...

  9. March 10th, 2018 Week 10th Saturday

    All good things must come to an end. 好景无常. Love is when the other person's happiness is more importa ...

  10. ansys19.0安装破解教程(图文详解)

    ansys19.0是一款非常著名的大型通用有限元分析(FEA)软件.该软件能够与多数计算机辅助设计软件接口,比如Creo, NASTRAN.Algor.I-DEAS.AutoCAD等,并能实现数据的共 ...