Java多线程:Future和FutureTask

一、Future

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

image.png

上源码:

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,关系图如下:

image.png

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方法获取结果,以上代码执行结果:

image.png

获取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线程池详解

posted @ 2023-01-31 16:33  卫旗  阅读(55)  评论(0编辑  收藏  举报