多线程与并发系列之FutureTask

概述

为了获取异步线程的返回结果,JDK1.5引入。

Callable

在介绍Callable接口前,得提到Runnable接口。Runnable接口是在Java多线程中表示线程的业务代码的抽象接口。但有个问题:run方法没有返回值,不能用于需要有返回值的应用场景。
源码:

@FunctionalInterface
public interface Callable<V> {
    
    
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

Callable是一个函数式泛型接口,其唯一的抽象方法call有返回值,返回值的类型为泛型形参的实际类型。有一个异常声明,容许方法内部的异常不经过捕获。

对比:Callable接口的实例不能作为Thread线程实例的target来使用;而Runnable接口实例可以作为Thread线程实例的target构造参数,开启一个Thread线程。

Java中的线程类型,只有一个Thread类,没有其他的类型。如果Callable实例需要异步执行,就要想办法赋值给Thread的target成员,一个Runnable类型的成员。为此,Java提供在Callable实例和Thread的target成员之间一个搭桥的类——FutureTask类。

Future

Future接口主要提供对并发任务的执行及获取其结果等3大功能:

  1. 判断并发任务是否执行完成
  2. 获取并发的任务完成后的结果
  3. 取消并发执行中的任务

源码:

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

方法说明:

  • V get():获取并发任务执行的结果,阻塞性的。如果并发任务没有执行完成,调用此方法的线程会一直阻塞,直到并发任务执行完成
  • V get(Long timeout, TimeUnit unit):获取并发任务执行的结果,阻塞性,但有阻塞时间限制,如果阻塞时间超过设定的timeout时间,该方法将抛出异常
  • boolean isDone():获取并发任务的执行状态。任务执行结束,则返回true
  • boolean isCancelled():获取并发任务的取消状态。任务完成前被取消,则返回true
  • boolean cancel(boolean mayInterruptRunning):取消并发任务的执行

FutureTask

其构造函数的参数为Callable类型,实际上是对Callable类型的二次封装,可以执行Callable的call方法。间接地继承Runnable接口,从而可以作为Thread实例的target执行目标。内部封装一个Callable实例,然后自身又作为Thread线程的target。

在外部,如何要获取Callable实例的异步执行结果,不是调用其call方法,而是需要通过FutureTask类的相应方法去获取。

基于AQS构建的Synchronizer,FutureTask既是Future、Runnable,又是包装Callable(如果是Runnable最终也会被转换为Callable ), 它是这两者的合体。

构造函数

callable实例属性必须要在FutureTask类的实例构造时进行初始化。其次,FutureTask内部有一个run方法。这个run方法是Runnable接口的抽象方法,在FutureTask类的内部提供了自己的实现。在Thread线程实例执行时,会将这个run方法作为target目标去异步执行。在FutureTask内部的run实现代码中,会执行其callable成员的call方法。执行完成后,将结果保存起来。

状态定义

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;

FutureTask中,一共有上面7种状态,其中New为实例的初始化状态, Completing和Interrupting为中间状态,其余四个为最终状态。

  1. New->Completing->Normal
  2. New->Completing->Exceptional
  3. New->Cancelled
  4. New->Interrupting->Interrupted

成员变量

    private Callable<V> callable;
    private Object outcome; // non-volatile, protected by state reads/writes
    private volatile Thread runner;
    private volatile WaitNode waiters;
  1. 有一个Callable类型的成员,代表异步执行的逻辑
  2. outcome属性,用于保存结果,可供FutureTask类的结果获取方法(如get)来获取

通过FutureTask类的get方法获取异步结果时,主线程也会被阻塞的。这一点和join一样,都是异步阻塞模式。

参考

猜你喜欢

转载自blog.csdn.net/lonelymanontheway/article/details/106035550
今日推荐