Future与FutureTask都是用于获取线程执行的返回结果。下面我们就对两者之间的关系与使用进行一个大致的介绍与分析

一、Future与FutureTask介绍

Future位于java.util.concurrent包下,它是一个接口

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;
}

Future接口中声明了5个方法,下面介绍一下每个方法的作用:

cancel方法用来取消任务,取消成功则返回true,取消失败则返回false。参数mayInterruptIfRunning设置为false,表示不允许在线程运行时中断,设置为true则表示允许。具体可分为以下三种情况:

1、如果任务已经完成,则无论mayInterruptIfRunning为true还是false,都返回false,这是因为你要取消的任务已经完成,则认为取消任务失败;

2、如果任务正在执行,则无论mayInterruptIfRunning为true还是false,都返回true。只不过mayInterruptIfRunning为true时线程会被中断,false时线程不会被中断会执行完。

3、如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,都返回true。

isCancelled方法用于判断任务是否被取消成功,cancel方法成功则返回 true,反之则为false。

isDone用于判断任务是否完成,  如果任务完成则返回true。任务完成包括正常结束、任务被取消、任务发生异常,都返回true

get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;

get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,抛出 java.util.concurrent.TimeoutException 异常

FutureTask 实现了RunnableFuture接口,而RunnableFuture则继承了Future<V>与Runnable接口,所以 FutureTask不仅实现了 Future<V>接口的所有方法,还具有自己的run方法,我们可以看下它的类图

、Future与FutureTask使用与分析

1、使用Future时,我们需要实现Callable接口,并通过ExecutorService接口的submit方法获取返回的Future对象,

2、使用FutureTask时,根据FutureTask的构造函数可以看到FutureTask既可以接收Callable的实现类,也可以接收Runnable的实现类。当你传入的是Callable的实现类时,可以获取线程执行的结果;传入Runnable的实现类时,由于Runnable的实现没有返回值,需要传入一个你设置的线程完成标识,也就是result,然后当线程结束时会把你传入的result原值返回给你,FutureTask的构造函数具体如下:

    public class FutureTask<V> implements RunnableFuture<V>{

     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);//runnable转化为callable
this.state = NEW; // ensure visibility of callable
}

接下来我们看下Future与FutureTask具体的使用代码:

        // 执行任务 实现Runnable
FutureTaskJobRunnable taskRun = new FutureTaskJobRunnable();
// 执行任务 实现Callable
FutureTaskJobCallable taskCall = new FutureTaskJobCallable();
String val = "ok";
// 线程运行成功后把,返回你传入的val值
FutureTask<String> futureTaskRun = new FutureTask<String>(taskRun, val);
// 线程运行,返回线程执行的结果
FutureTask<String> futureTaskCall = new FutureTask<String>(taskCall); //声明线程池
ExecutorService executor = Executors.newCachedThreadPool();
//Future
Future<String> future = executor.submit(taskCall);
System.out.println(future.get());
//FutureTask
executor.submit(futureTaskCall);
System.out.println(futureTaskCall.get());
//FutureTask自定义线程执行
new Thread(futureTaskRun).start();
System.out.println(futureTaskRun.get());
public class FutureTaskJobCallable implements Callable<String>{

    public String call() throws Exception {
System.out.println("FutureTaskJobCallable已经执行了哦");
Thread.sleep(1000);
return "返回结果";
} } public class FutureTaskJobRunnable implements Runnable { public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("FutureTaskJobRunnable已经执行了哦");
} }

根据上面的代码我们从ExecutorService接口中submit方法入手,看下AbstractExecutorService类对submit方法的具体实现。

    public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
} public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
} public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
} protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
} protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}

可以看到当你使用submit方法提交任务时,都会通过newTaskFor方法转换成FutureTask对象,所以我们具体分析下上面代码中的三种情况:

1、如果你传入的是自己实现的Runaable类或者Callable类,那么sumbit方法自然会帮你自动封装为FutureTask对象,运行后通过Future对象获取结果。

2、你传入的已经是个自己构造的FutureTask对象,由于FutureTask其实是实现了Runnable接口的,它本身就是个Runaable实现类, sumbit方法还是会将它视为Runnable类来进行封装,并最终会执行FutureTask自己的run方法,一系列实现都在你传入的FutureTask对象内完成,所以你可以直接通过自己构建的FutureTask获取结果;

3、自己单独声明线程运行,跟第2点类似,FutureTask本身就是个Runnabel实现类,自然可以做为参数传入Thread运行;

那么我们把自定义的Runnable、Callable实现类做为参数构造FutureTask后,FuttureTask是如何运行的呢,我们可以看下FuttureTask中具体的代码实现

//你传入的Runnable与Callable实现类都会在构造函数中转化为Callable
private Callable<V> callable; public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;//你传入的实现类
if (c != null && state == NEW) {
V result;//返回值
boolean ran;
try {
result = c.call();//运行后返回结果
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}

可以看到FutureTask类本身的run方法,就是执行Runnable、Callable的实现类并获取返回结果的过程。

所以ExecutorService接口中submit方法归根结底还是要把你传入的对象封装成FutureTask对象,并通过FutureTask类的内部实现来获取结果的,返回的Future接口对象也要依赖于FutureTask实例化的,所以无论是直接传入自己的Runnable、Callable实现类还是构建FutureTask传入,本质上都是通过FutureTask去实现,没有什么区别;

以上就是对Future与FutureTask两者关系的一个大致的介绍与分析,其中如有不足与不正确的地方还望指出与海涵。

关注微信公众号,查看更多技术文章。

java中Future与FutureTask使用与分析的更多相关文章

  1. 【JAVA】java中Future、FutureTask的使用

    如今的系统基本都是分布式的,各个系统各司其职的,不可能一个系统干了全部系统的事. 所以系统之间的交互就越来越多了.那么系统之间的交互仅仅有通过网络来交互了,而网络必定会存在延时的情况. 比方A系统的一 ...

  2. Java中Comparable和Comparator接口区别分析

    Java中Comparable和Comparator接口区别分析 来源:码农网 | 时间:2015-03-16 10:25:20 | 阅读数:8902 [导读] 本文要来详细分析一下Java中Comp ...

  3. java 中 “文件” 和 “流” 的简单分析

    java 中 FIle 和 流的简单分析 File类 简单File 常用方法 创建一个File 对象,检验文件是否存在,若不存在就创建,然后对File的类的这部分操作进行演示,如文件的名称.大小等 / ...

  4. java中Future的使用

    文章目录 创建Future 从Future获取结果 取消Future 多线程环境中运行 java中Future的使用 Future是java 1.5引入的一个interface,可以方便的用于异步结果 ...

  5. Java 多线程Future和FutureTask

    Future表示一个任务的周期,并提供了相应的方法来判断是否已经完成或者取消,以及获取任务的结果和取消任务. Future接口源码: public interface Future<V> ...

  6. Java中的Enum的使用与分析

    使用name()方法和valueOf(String)方法可以在枚举类型对象和字符串之间方便得转换.如果valueOf(String)方法的参数不是该枚举类型合法的字符串,则会抛出IllegalArgu ...

  7. Java中参数传递时值传递的机制分析

    参数传递是什么?      在C的函数或是JAVA的方法中,向一个函数或方法内部传递一个参数,比如:   void fun( int num ){     num+=2 ; }   int a = 3 ...

  8. java中的==、equals()源码分析

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...

  9. Java 中 ThreadLocal 内存泄露的实例分析

    前言 之前写了一篇深入分析 ThreadLocal 内存泄漏问题是从理论上分析ThreadLocal的内存泄漏问题,这一篇文章我们来分析一下实际的内存泄漏案例.分析问题的过程比结果更重要,理论结合实际 ...

随机推荐

  1. 启动apache 找不到 mbstring.dll

    启动appserv时 提示 无法启动此程序 因为计算机中丢失php mbstring.dll   这种原因一般都是组件加载顺序引起的,在php.ini文件里确保 extension=php_mbstr ...

  2. centos7 安装mysql--python模块出现EnvironmentError: mysql_config not found和error: command 'gcc' failed with exit status 1

    要想使python可以操作mysql 就需要MySQL-python驱动,它是python 操作mysql必不可少的模块. 下载地址:https://pypi.python.org/pypi/MySQ ...

  3. LINUX7安装Oracle11g单实例小结

    LINUX7安装Oracle11g遇到问题如下,记录 添加组: groupadd -g 1000 oinstall #报错:提示组被占用 #useradd: group 'oinstall' does ...

  4. [LeetCode&Python] Problem 268. Missing Number

    Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...

  5. XML中DTD,XSD的区别与应用

    XML我们并不陌生,在企业级应用中有很广的用途.具体就不再说,下面介绍一下DTD,XSD的区别并以XSD为例看spring中定义与使用.1.DTD(Documnet Type Definition)D ...

  6. C#LinQ语法

    Unity开发VR之Vuforia 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...

  7. Unity 3D光源-Spot Light聚光灯用法详解、模拟手电筒、台灯等线性教程

    Unity4大光源之聚光灯 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享. ...

  8. HPU第三次积分赛-D:Longest Increasing Subsequence(DP)

    Longest Increasing Subsequence 描述 给出一组长度为n的序列,a1​,a2​,a3​,a4​...an​, 求出这个序列长度为k的严格递增子序列的个数 输入 第一行输入T ...

  9. 基于BP的B/S架构破解

    思路历程: 1.获取用户名 2.获取密码字典 3.使用BP爆破 案例: 管理人员在平时的网络生活中没有良好的个人信息保护,让不法份子有机可乘.例如WordPress等的类似网站使用PHP开发,虽然功能 ...

  10. 浅谈log4j-6-xml配置 转自godtrue

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SY ...