Java多线程:Future和FutureTask

Posted 旗smile

tags:

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

一、Future

Future是一个接口,所有方法如下:

上源码:

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

  • cancel:取消任务(mayInterruptIfRunning是否中断正在执行的任务)。
  • isCancelled:任务是否取消
  • isDone:任务是否执行完成。
  • get:获取任务结果
  • get(long timeout, TimeUnit unit):有等待时间的获取任务结果。

二、FutureTask

FutureTask是一个类,实现了RunnableFuture接口,RunnableFuture接口继承了RunnableFuture,关系图如下:

FutureTask有两个构造函数:

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对象,第二个构造函数传入Runnable对象和一个V类型的对象,然后在函数中将这两个参数构造成一个Callable对象。可见FutureTaskFuture的核心就是要执行Callable并获取返回结果。

FutureTask中的几种状态:

/**
 *
 * 可能的状态转换:
 * NEW -> COMPLETING -> NORMAL
 * NEW -> COMPLETING -> EXCEPTIONAL
 * NEW -> CANCELLED
 * NEW -> INTERRUPTING -> INTERRUPTED
 */
private volatile int state;
private static final int NEW          = 0;
private static final int COMPLETING   = 1;
private static final int NORMAL       = 2;
private static final int EXCEPTIONAL  = 3;
private static final int CANCELLED    = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED  = 6;

查看源码,发现状态共有七种,初始化为NEW,运行时仅在set、setException和cancel方法中会转换为终端状态。终端状态共四种:NORMAL结果正常、EXCEPTIONAL结果异常、CANCELLED任务取消、INTERRUPTED任务中断,可能的状态转换源码中注释已写清楚。

三、示例

Future在线程池中主要做为一个返回(submit方法),用于接收执行完成的结果,FutureTask则是具体实现。
测试代码:

public class ExecutorTest1 

    public static void main(String[] args) 
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        ExecutorTest1 test1 = new ExecutorTest1();
        Future<String> futureTest = executorService.submit(() -> test1.say("测试返回值"));
        executorService.shutdown();
    

    public String say(String a)
        System.out.println("执行了say方法");
        return "test"+a;
    


以上代码,执行了say方法,获取到了futureTest对象,但是futureTest对象不能直接使用,需要调用get方法获取结果,以上代码执行结果:

获取Future对象结果代码示例:

public class ExecutorTest1 

    public static void main(String[] args) 
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        ExecutorTest1 test1 = new ExecutorTest1();
        Future<String> futureTest = executorService.submit(() -> test1.say("测试返回值"));
        try 
            String s = futureTest.get();
            System.out.println(s);
         catch (InterruptedException e) 
            e.printStackTrace();
         catch (ExecutionException e) 
            e.printStackTrace();
        
        executorService.shutdown();
    

    public String say(String a)
        System.out.println("执行了say方法");
        return "test"+a;
    


可见要执行有返回值的线程,需要用Future来接收。那么FutureTask在哪里使用了呢,在执行方法的时候将传入的Callable对象或者Runnable对象封装成FutureTask对象,源码如下:

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;

newTaskFor方法如下:

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) 
    return new FutureTask<T>(runnable, value);

四、结果

Future和FutureTask的核心作用是获取有返回值的线程结果。

Java多线程:Future和FutureTask

Java线程池详解

以上是关于Java多线程:Future和FutureTask的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程:Future和FutureTask

Java线程和多线程(十三)——Callable,Future,FutureTask

Java多线程:Callable,Future,FutureTask

Java多线程Future与FutureTask

Java多线程编程:CallableFuture和FutureTask浅析

Java多线程研究06-带返回值的线程定义接口Callable以及Future,FutureTask的使用