【小家java】一个例子让就能你彻底理解Java的Future模式,Future类的设计思想(上)

简介: 【小家java】一个例子让就能你彻底理解Java的Future模式,Future类的设计思想(上)

Futrue模式简介


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


image.png


Future模式的处理流程:


image.png


实现Future模式的客户端在拿到这个返回结果后,并不急于对它进行处理,而是去调用其它的业务逻辑,使call()方法有充分的时间去处理完成,这也是Future模式的精髓所在。在处理完其他业务逻辑后,最后再使用处理比较费时的Future数据。这个在处理过程中,就不存在无谓的等待,充分利用了时间,从而提升了系统的响应和性能。


JDK内置实现介绍


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


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


FutureTask该类在JDK5、6版本的实现和JDK8中的实现有较大的差异.JDK8后退该类的性能进行了较大的提升,后面会结合源码级别进行讲解。


例子剖析:Futrue模式


下面这个例子总体来说是个非常通俗易懂的例子,并且讲解得也比较详细,愿读者能够读懂,有不懂得可以随时留了言哦


先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材。网上购买厨具比较方便,食材去超市买更放心。


实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材。所以,在主线程里面另起一个子线程去网购厨具。


但是,子线程执行的结果是要返回厨具的,而run方法是没有返回值的。所以,这才是难点,需要好好考虑一下。


    代码模拟:

package test;
public class CommonCook {
    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        // 第一步 网购厨具
        OnlineShopping thread = new OnlineShopping();
        thread.start();
    //通过join线程来阻断主线程,以先保证厨具送到才继续往下走
        thread.join();  
        // 第二步 去超市购买食材
        Thread.sleep(2000);  // 模拟购买食材时间
        Shicai shicai = new Shicai();
        System.out.println("第二步:食材到位");
        // 第三步 用厨具烹饪食材
        System.out.println("第三步:开始展现厨艺");
        cook(thread.chuju, shicai);
        System.out.println("总共用时" + (System.currentTimeMillis() - startTime) + "ms");
    }
    // 网购厨具线程的线程类 
    static class OnlineShopping extends Thread {
        private Chuju chuju;
        @Override
        public void run() {
            System.out.println("第一步:下单");
            System.out.println("第一步:等待送货");
            try {
                Thread.sleep(5000);  // 模拟快递小哥送货时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("第一步:快递送到");
            chuju = new Chuju(); //拿到厨具了
        }
    }
    //  用厨具烹饪食材的线程  做饭肯定得厨具、食材都有了才能开始  所以传进去
    static void cook(Chuju chuju, Shicai shicai) {}
    // 厨具类
    static class Chuju {}
    // 食材类
    static class Shicai {}
}

运行结果:

第一步:下单
第一步:等待送货
第一步:快递送到
第二步:食材到位
第三步:开始展现厨艺
总共用时7013ms


从总用时我们可以看到,多线程已经失去了意义。在厨具送到期间,我们不能干任何事。对应代码,就是调用join方法阻塞主线程。

其实这里面虽然用到了Thread,但其实并没有起到多线程的作用。因为很显然,一个join,使得一切都串行化了。那有人会问,不阻塞行不行呢?答案显然是不行的,因为还没有厨具的情况下,你不能做饭。


从代码来看的话,run方法不执行完,属性chuju就没有被赋值,还是null。换句话说,没有厨具,怎么做饭。

Java现在的多线程机制,核心方法run是没有返回值的;如果要保存run方法里面的计算结果,必须等待run方法计算完,无论计算过程多么耗时。

面对这种尴尬的处境,程序员就会想:在子线程run方法计算的期间,能不能在主线程里面继续异步执行???


Where there is a will,there is a way!!!


相关文章
|
4月前
|
Java 编译器 API
Java 密封类:精细化控制继承关系
Java 密封类:精细化控制继承关系
338 83
|
2月前
|
安全 Java 数据建模
Java记录类:简化数据载体的新选择
Java记录类:简化数据载体的新选择
230 101
|
2月前
|
安全 Java 开发者
Java记录类:简化数据载体的新方式
Java记录类:简化数据载体的新方式
281 100
|
3月前
|
安全 IDE Java
Java记录类型(Record):简化数据载体类
Java记录类型(Record):简化数据载体类
390 120
|
1月前
|
存储 Java 索引
用Java语言实现一个自定义的ArrayList类
自定义MyArrayList类模拟Java ArrayList核心功能,支持泛型、动态扩容(1.5倍)、增删改查及越界检查,底层用Object数组实现,适合学习动态数组原理。
85 4
|
1月前
|
IDE JavaScript Java
在Java 11中,如何处理被弃用的类或接口?
在Java 11中,如何处理被弃用的类或接口?
147 5
|
1月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
135 1
|
1月前
|
Java Go 开发工具
【Java】(8)正则表达式的使用与常用类分享
正则表达式定义了字符串的模式。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
198 1
|
1月前
|
存储 Java 程序员
【Java】(6)全方面带你了解Java里的日期与时间内容,介绍 Calendar、GregorianCalendar、Date类
java.util 包提供了 Date 类来封装当前的日期和时间。Date 类提供两个构造函数来实例化 Date 对象。第一个构造函数使用当前日期和时间来初始化对象。Date( )第二个构造函数接收一个参数,该参数是从1970年1月1日起的毫秒数。
140 1
|
1月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
156 1