专栏首页JAVA杂谈多线程设计模式 - Future模式之JAVA原生实现

多线程设计模式 - Future模式之JAVA原生实现

JDK内置的Future设计模式主要使用到了Callable接口和FutureTask类。

Callable

Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其他线程执行的任务。Callable接口的定义如下:

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */  
    V call() throws Exception;
}

Callable的类型参数是返回值的类型。例如:

Callable<Integer>表示一个最终返回Integer对象的异步计算。

FutureTask

在认识FutureTask之前我们先来了解一下保存计算结果的接口类Future 在实际应用中可以启动一个计算,将Future对象交给某个线程,然后执行其他操作。Future对象的所有者在结果计算好之后就可以获得它。Future接口具有下面的方法:

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled(); boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

第一个get方法的调用被阻塞,直到计算完成。如果在计算完成之前,第二个get方法的调用超时,抛出一个TimeoutException异常。如果运行该计算的线程被中断,两个方法都将抛出InterruptedException。如果计算已经完成,那么get方法立即返回。如果计算还在进行,isDone方法返回false;如果完成了,则返回true。

可以用cancel方法取消该计算。如果计算还没有开始,它被取消且不再开始。如果计算处于运行之中,那么如果mayInterrupt参数为true,它就被中断。

认识了Future类后我们再来认识FutureTask,FutureTask包装器是一种非常便利的机制,同时实现了FutureRunnable接口。FutureTask有2个构造方法:

public FutureTask(Callable<V> callable) {
    if (callable == null) throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
 }

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

通常,我们会使用Callable示例构造一个FutureTask对象,并将它提交给线程池进行处理,下面我们将展示这个内置的Future模式的使用。

public class RealData implements Callable<String> {
    private String param;
    public RealData(String param){
        this.param = param;
    }
    @Override 
    public String call() throws Exception {
        StringBuffer sb = new StringBuffer();
        for(int i = 0 ; i< 10 ;i++){
            sb.append(param); try {
                Thread.sleep(100);
            }catch (InterruptedException e){

            }
        }
        return sb.toString();
    }
}

上述代码实现了Callable接口,它的Call方法会构造我们需要的真实数据并返回,当然这个过程比较缓慢,这里使用Thread.sleep()来模拟它:

public class FutureMain {
    public static void main(String[] args)
            throws ExecutionException, InterruptedException {
        //构造FutureTask
        FutureTask<String> futureTask = new FutureTask<String>(new RealData("xxx"));
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        //执行FutureTask,发送请求
        //在这里开启线程进行RealData的call()执行
        executorService.submit(futureTask);

        System.out.println("请求完毕。。。");
        try {
            //这里可以进行其他额外的操作,这里用sleep代替其他业务的处理
            Thread.sleep(200);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        //获取call()方法的返回值
        //如果此时call()方法没有执行完成,则依然会等待
        System.out.println("真实数据:"+futureTask.get());
    }
}

上述代码就是使用Future模式的典型。构造FutureTask时使用实现Callable接口的实现类,告诉FutureTask我们需要的数据应该有返回值。然后将FutureTask提交给线程池,接下来我们不用关心数据是怎么产生的,可以去做其他的业务逻辑处理,然后在需要的时候调用FutureTask.get()得到实际的数据。

Future模式在日常业务中处理复杂业务时会经常用到,希望大家都能掌握。

本文分享自微信公众号 - JAVA日知录(java_daily),作者:单一色调

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 数据库设计方法论 - 继承

    继承这个概念做java开发的同学应该都很熟悉了,继承指的是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具...

    JAVA日知录
  • 使用Kubeadm搭建Kubernetes集群

    今天我们先重点说一下kubelet组件,kubelet 主要负责同容器运行时(比如 Docker 项目)打交道。而这个交互所依赖的,是一个称作 CRI(Cont...

    JAVA日知录
  • RocketMQ进阶-延时消息

    在开发中经常会遇到延时任务的需求,例如在12306购买车票,若生成订单30分钟未支付则自动取消;还有在线商城完成订单后48小时不评价 ,自动5星好评。像这类在某...

    JAVA日知录
  • 朋友圈的一些高级玩法

    大多数人每天都要刷朋友圈,但很多人可能觉得朋友圈只有三个主要功能:发图文、视频以及转发动态。其实,朋友圈还有不少新奇玩法,下面来说道说道。

    数据森麟
  • 如何解决eclipse远程服务器上面的Rabbitmq连接超时问题?

    1、嗯,问题呢,就是一开始安装好RabbitMQ,练习了一下RabbitMQ的使用,但是呢,过了一段时间,我来复习的时候,发现运行出现下面的错误了。后来想想,是...

    别先生
  • 软件测试如何快速入行

    王豆豆
  • 软件测试老员工如何突破职业瓶颈?

    任何一个职业都有瓶颈期的时候,软件测试人员也是如此。倦怠期、瓶颈期都是一个人在工作和生活上必须面对的一个坡,爬过去了一切安好,没爬过去可能回到原点。

    新梦想IT职业教育
  • 线性混合模型系列四:矩阵求解

    这篇文章通过R语言代码的形式,介绍给定方差组分的情况下,如何根据两种矩阵求解的方法分别计算BLUE值和BLUP值。

    邓飞
  • 如何对C4C UI上的手机号码字段加上自定义验证逻辑

    WebUI上的mobile phone允许输入字母,C4C UI也是如此。中国客户要求手机号码只能输入数字:

    Jerry Wang
  • 用一张图理解SVM的脉络

    SVM在之前的很长一段时间内是性能最好的分类器,它有严密而优美的数学基础作为支撑。在各种机器学习算法中,它是最不易理解的算法之一,要真正掌握它的原理有一定的难度...

    SIGAI学习与实践平台

扫码关注云+社区

领取腾讯云代金券