Java 多线程的设计模式之 Future

Future 设计模式核心原理图:

这里写图片描述

client端通过 FutureData 发送一个执行耗时操作的请求,FutureData 则直接返回一个回调接口的引用(Data 接口,用于返回获取到的真正结果),然后在 FutureData 内部再另起一个线程去执行真正的耗时操作。当 client 端 执行了获取结果的方法时,如果执行完成,则返回结果。如果还在执行中,则会进入线程等待状态,一直等到执行完成进行线程唤醒之后才能拿到结果。

这个设计模式在 Java JDK 中已经被实现了,这里先看一下自测代码,从最里层开始看:

自测 Future 模式实现
  • RealData 实现类
public class RealData {

    private String data;

    public RealData(String data) throws InterruptedException {
        System.out.println("模拟数据加载中。。。");
        TimeUnit.SECONDS.sleep(5);
        this.data = data;
    }

    public String getResult() {
        return data + " - real data";
    }
}

上面流程图中标注的 RealData 也要实现 Data 接口,这里自己实现的话,其实也是可以省略的,自己写一个获取方法,效果也是一样的。这里模拟的是执行耗时操作。

  • FutureData 实现类
public class FutureData implements Data {

    private boolean isReady;// 是否准备好了。 也就是耗时操作是否执行完成了。
    private RealData data;// 真实数据操作对象

    public synchronized void setRequest(RealData data) {
        if (isReady) {
            return;
        }
        this.data = data;
        isReady = true;
        notify();
    }

    @Override
    public synchronized String getResult() throws InterruptedException {
        if (!isReady) {
            System.out.println("等待数据返回中。。。");
            wait();
        }
        return data.getResult();
    }
}

这里说一下,因为 RealData 的耗时操作直接在构造方法中写的,所以,当进入 setRequest 方法的时候,说明 RealData 已经实例化好了,也就是耗时操作已经执行完成了。这里 FutureData 也就是 RealData 的一个代理,包装着 RealData 的耗时操作过程。

wait() 和 notify() 方法 一定要配合 synchronize 关键字使用。
  • Client 端实现
public class Client {

    public Data setRequest(String requestString) {
        FutureData data = new FutureData();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("client run : " + System.currentTimeMillis());
                    data.setRequest(new RealData(requestString));// 当 RealData 的构造方法执行完成之后,才会进入到 setRequest的方法中。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        return data;
    }
}
  • 调用代码
public class Main {
    /**
     * Futrue 设计模式,
     * client端 发送某个耗时请求 - >  FutrueData 代理对象 先返回一个 假对象,然后其内部开启线程进行真实请求操作 -- >  RealData 真实处理对象,处理结束之后,回调数据给 代理对象,代理对象再进行通知 client端
     */

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Client client = new Client();
        Data data = client.setRequest("this is test");
        System.out.println("main : " + System.currentTimeMillis());
        System.out.println(data.getResult()); // 会进入线程等待状态。

    }
}
JDK 内部 Future 实现

上面也说了,这个设计模式 JDK 内部是已经实现了这个机制。 FutureTask 作为我们的代理类,它实现了 Runnable 接口,本身就作为一个独立的线程执行,但是它没有start 方法,必须配合线程池使用。因为 FutureTask 的传入对象是 Callable(接口) 类型,所以,我们的 RealData 类也需要实现 Callable 接口。真实数据最终会通过 Callable 接口的 call() 方法传递给 FutureTask 。

  • 实现代码:
public class RealData_1 implements Callable<String> {

    private String data;

    public RealData_1(String data) {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("real data 1");
        this.data = data;
    }

    @Override
    public String call() throws Exception {
        System.out.println("real data 1 call()");
        return data;
    }
}
  • 调用方式:
 public static void main(String[] args) throws InterruptedException, ExecutionException {
//        Client client = new Client();
//        Data data = client.setRequest("this is test");
//        System.out.println("main : " + System.currentTimeMillis());
//        System.out.println(data.getResult());

        /**
         * Java jdk 内置 FutureTask 是一个线程类,必须使用配合线程池调用。
         */
        FutureTask futureTask = new FutureTask(new RealData_1("this is test jdk future"));
        ExecutorService exe = Executors.newFixedThreadPool(1);

        exe.submit(futureTask);

        System.out.println(futureTask.get());

    }

最后说一下线程池的 submit 方法和 execute 方法的区别:

  • submit 可以传入实现 Callable接口的实例对象。
  • submit 方法有返回值。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值