打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Future设计模式

一、什么是Future模式:
Future设计模式是Java多线程开发常用设计模式。一句话,将客户端请求的处理过程从同步改为异步,以便将客户端解放出来,在服务端程序处理期间可以去干点其他事情,最后再来取请求的结果。好处在于整个调用过程中不需要等待,可以充分利用所有的时间片段,提高系统的响应速度。

这里就以java.util.concurrent.Future为例,简单说一下Future的具体工作方式。Future对象本身可以看作是一个显式的引用,一个对异步处理结果的引用。由于其异步性质,在创建之初,它所引用的对象可能还并不可用(比如尚在运算中,网络传输中或等待中)。这时得到Future的程序流程如果并不急于使用Future所引用的对象,那么它可以做其它任何想做的事儿,当流程进行到需要Future背后引用的对象时,可能有两种情况:

  1. 希望能看到这个对象可用,并完成一些相关的后续流程。如果实在不可用,也可以进入其它分支流程。
  2. “没有你我的人生就会失去意义,所以就算海枯石烂,我也要等到你。”(当然,如果实在没有毅力枯等下去,设一个超时也是可以理解的)

第一种情况,可以通过调用Future.isDone()判断引用的对象是否就绪,并采取不同的处理;
第二种情况,则只需调用get()或get(long timeout, TimeUnit unit)通过同步阻塞方式等待对象就绪。实际运行期是阻塞还是立即返回就取决于get()的调用时机和对象就绪的先后了。(如下图所示)


Future流程图

二、Future模式举例

Data接口类

public interface Data {    String getResult() throws InterruptedException;}

FutureData实现类

public class FutureData implements Data {    RealData realData = null; // FutureData是RealData的封装    boolean isReady = false; // 是否已经准备好    public synchronized void setRealData(RealData realData) {        if (isReady)            return;        this.realData = realData;        isReady = true;        notifyAll(); // RealData已经被注入到FutureData中了,通知getResult()方法    }    @Override    public synchronized String getResult() throws InterruptedException {        if (!isReady) {            System.out.println("还没有好,还需等待!");            wait(); // 一直等到RealData注入到FutureData中            System.out.println("好了");        }        return realData.getResult();    }}

RealData 实现类

public class RealData implements Data {    protected String data;    public RealData(String data) {        // 利用sleep方法来表示RealData构造过程是非常缓慢的        try {            System.out.println("RealData生成中...");            Thread.sleep(4000);        }        catch (InterruptedException e) {            e.printStackTrace();        }        this.data = data;    }    @Override    public String getResult() {        return data+"-RealData";    }}

Client 客户端类

public class Client {    public Data request(final String string) {        final FutureData futureData = new FutureData();        new Thread(new Runnable() {            @Override            public void run() {                // RealData的构建很慢,所以放在单独的线程中运行                RealData realData = new RealData(string);                futureData.setRealData(realData);            }        }).start();        System.out.println("先直接返回FutureData");        return futureData; // 先直接返回FutureData    }}

Test调用测试

public class Test{    public static void main(String[] args) throws InterruptedException {        Client client = new Client();        // 这里会立即返回,因为获取的是FutureData,而非RealData        System.out.println("请求数据");        Data data = client.request("name");        // 这里可以用一个sleep代替对其他业务逻辑的处理        System.out.println("等待的时间里面,干点其它事情");        Thread.sleep(2000);        System.out.println("其它事情干完了,看看是否有数据返回?");        // 使用真实数据        System.out.println("真实数据返回(如果还没有返回堵塞等待)=" + data.getResult());    }}

测试结果

请求数据先直接返回FutureData等待的时间里面,干点其它事情RealData生成中...其它事情干完了,看看是否有数据返回?还没有好,还需等待!好了真实数据返回(如果还没有返回堵塞等待)=name-RealData

三、Future模式的JDK内置实现

由于Future是非常常用的多线程设计模式,因此在JDK中内置了Future模式的实现。这些类在java.util.concurrent包里面。其中最为重要的是FutureTask类,它实现了Runnable接口,作为单独的线程运行。在其run()方法中,通过Sync内部类调用Callable接口,并维护Callable接口的返回对象。当使用FutureTask.get()方法时,将返回Callable接口的返回对象。同样,针对上述的实例,如果使用JDK自带的实现,则需要作如下调整。

首先,Data接口和FutureData就不需要了,JDK帮我们实现了。

RealData改成RealDataJdk

import java.util.concurrent.Callable;public class RealDataJdk implements Callable<String> {    protected String data;    public RealDataJdk(String data) {        this.data = data;    }    @Override    public String call() throws Exception {        // 利用sleep方法来表示真是业务是非常缓慢的        try {            System.out.println("RealData生成中...");            Thread.sleep(1000);        }        catch (InterruptedException e) {            e.printStackTrace();        }        return data + "-RealData";    }}

Test 改成 TestJdk

import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.FutureTask;public class TestJdk {    public static void main(String[] args)            throws InterruptedException, ExecutionException {        FutureTask<String> futureTask = new FutureTask<String>(new RealDataJdk("name"));        ExecutorService executor = Executors.newFixedThreadPool(1); // 使用线程池        // 执行FutureTask,相当于上例中的client.request("name")发送请求        executor.submit(futureTask);        // 这里可以用一个sleep代替对其他业务逻辑的处理        // 在处理这些业务逻辑过程中,RealData也正在创建,从而充分了利用等待时间        System.out.println("数据=" + futureTask.get());        Thread.sleep(2000);        // 使用真实数据        // 如果call()没有执行完成依然会等待        System.out.println("数据=" + futureTask.get());    }}
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
高并发Java(7):并发设计模式
Java多线程编程中Future模式的详解
多线程设计模式- Future模式
Future和FutureTask
线程-1、创建线程的方式及实现
Java多线程21:多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服