最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

Java多线程:Future和FutureTask

来源:博客园

一、Future

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

上源码:

package java.util.concurrent;public interface Future {    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 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 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 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 ftask = newTaskFor(task, null);    execute(ftask);    return ftask;}public  Future submit(Runnable task, T result) {    if (task == null) throw new NullPointerException();    RunnableFuture ftask = newTaskFor(task, result);    execute(ftask);    return ftask;}public  Future submit(Callable task) {    if (task == null) throw new NullPointerException();    RunnableFuture ftask = newTaskFor(task);    execute(ftask);    return ftask;}

newTaskFor方法如下:

protected  RunnableFuture newTaskFor(Runnable runnable, T value) {    return new FutureTask(runnable, value);}

四、结果

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

Java多线程:Future和FutureTask

Java线程池详解

关键词: 构造函数 获取任务 等待时间