(6)Future深入理解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(6)Future深入理解相关的知识,希望对你有一定的参考价值。

参考技术A Future 表示 异步计算 的结果,提供了一些方法来检查是否计算完成,等待 计算完成和取回计算结果 。 

当运算完成后只能通过 get 方法来获取结果。 必要时会 阻塞当前线程 直到计算 完成 。 

通过 cancel 方法可以取消任务的执行。 

其它方法 用来 决定任务 是否正常执行 完成还是被取消 了,任务执行 完成 的任务 不能被取消。  

如果你想要使用Future的 取消任务执行的功能 而不 不需要 取得 计算结果 ,那么你可以声明范性为 Future,然后 return null 作为计算的结果。 

FutureTask 是Future的实现,并且它也实现了 Runnable接口 ,可以通过 execute 方法来执行。例如:上面 submit 的运行方式也可以用下面的方式来替代。

FutureTask是异步任务执行最重要的一个自带的内部实现类,下一篇研究FutureTask的实现原理。  

内存一致性影响 :异步的计算的任务 在 Future.get() 满足happen-before ,即Future.get()先执行的话将优先获得执行结果。

表示Future.get() 返回的执行结果。

尝试取消任务的执行 ,如果任务已经执行完成,或者已经被取消了,又或者由于其它原因不能取消,那么这个 尝试可能失败 。 

如果任务 还未执行 ,并且cancel被调用成功,那么这个任务将不会被执行。 

如果任务已经 开始执行 了,mayInterruptIfRunning 参数来决定 是在 停止任务 过程中是否可以 中断 。 

调用cancel方法返回后, isDone 方法调用的结果将总是返回 true ,如果 cancel 方法返回true,那么isCancelled也将返回true。 

mayInterruptIfRunning :如果为 true ,表示执行中的任务可以被中断,否则,可以等待执行中的任务完成。 

如果不能取消,返回false(例如它已经执行完成了),否则返回true。

如果在任务正常完成前,任务被取消,返回 true

如果任务执行完成,返回true, 可能由于正常中止,异常或者被cancel,这些情况下该方法返回true

返回任务执行结果,需要的话会等待任务执行完成。 

返回任务执行结果

返回任务执行结果,需要的话会等待任务执行完成,等待时间不超过超市时长。

返回任务执行结果

Future模式理解及FutureTask应用场景

一、 Future模式理解

先说一下为什么要用future模式:两个任务没有必然的前后关系,如果在一个线程中串行执行,就有些浪费时间,不如让两个线程去并行执行这两个任务,执行完了到主线程去汇报就可以了。(让任务后台运行,不阻塞线程)

则使用Future模式耗费的时间为: max(TimeofTask1,TimeofTask2)。串行的话则是TimeofTask1+TimeofTask2。

接下来使用代码的类图:

 

先贴出源码,可以先看下源码理解一下,怎么使用就成了future模式。

Interface:

public interface Data {
    public String getResult();
}

RealData:

public class RealData implements Data{
    protected final String result;

    public RealData(String para) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10; i++) {
            sb.append(para);
        }
        try {
            // 这里使用sleep,模拟很慢的构造RealData过程
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result = sb.toString();
    }

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

FutureData

// FutureData是RealData的包装
public class FutureData implements Data {
    protected RealData realData = null;
    protected boolean isReady = false;
    public synchronized void setRealData(RealData realdata){
        if (isReady){
            return;
        }
        this.realData = realdata;
        isReady = true;
        // RealData注入完毕以后,通知getResult()
        notifyAll();
    }

    @Override
    public synchronized String getResult() {
        while (!isReady){
            try {
                // 等待RealData被注入,直到被notify
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return realData.result;
    }
}
View Code

首先我们要明确,RealData是我们真正需要的数据,FutureData只是做了一层封装,可以实现在得到RealData的过程中不阻塞当前线程。

我们重点来看FutureData,就两个方法,暂且把setRealData叫做注入数据方法,getResult是拿到最终数据方法。

一个状态位isReady,等待RealData注入完毕,就可以getResult了。没注入完毕,则阻塞当前线程。

有了这些信息,我们可以这样想,这个构建RealData很费时间,不如把这个构建任务扔到一个线程里去,当前线程去做其他事情。

使用方法:

public class FutureMainByMyself {
    public Data request(final String queryStr){
        // futureData包装了RealData
        final FutureData futureData = new FutureData();
        new Thread(){
            // RealData构建很慢,放在一个线程里慢慢去构建
            @Override
            public void run() {
                RealData realData = new RealData(queryStr);
                futureData.setRealData(realData);
            }
        }.start();
        return futureData;
    }

    public static void main(String[] args) {
        FutureMainByMyself client = new FutureMainByMyself();
        Data data = client.request("name");
        System.out.println("请求完毕");
        //这里才是真实的数据
        try {
            //这里的sleep代表了其他的业务逻辑,
            //在处理这些业务逻辑的同时,RealData被创建,从而充分利用了时间
            System.out.println(LocalTime.now());
            Thread.sleep(2000);
            System.out.println(LocalTime.now());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("数据=" +data.getResult() + " " + LocalTime.now());

    }
}

二、FutureTask应用场景和源码解析

FutureTask使用场景上面只是大致说了一下,下面我们来举一个具体的场景:API网关。

比方说用户打开一个订单页面:可能要查许多接口:订单信息,积分信息,退换货信息,这时候如果串行去查这么多东西,很费时间。

这些信息是没有必要的先后关系的,所以可以做出并行的。平时我们用软件也能注意到,先出来这块信息,再出来那块信息,这就是并行去查的结果,当然也可以等所有信息都拿到,再同时返回。

FutureTask源码解析:http://www.cnblogs.com/NoYone/p/8863083.html

 

以上是关于(6)Future深入理解的主要内容,如果未能解决你的问题,请参考以下文章

深入理解JVM—Java 6 JVM参数配置说明

深入浅出Node.js - 理解Buffer

深入理解MySQL的间隙锁

《深入理解Android 卷III》第六章 深入理解控件(ViewRoot)系统

深入理解Stream之原理剖析

深入理解lambda的奥秘