Callable ,Future ,FutureTask 介绍

165 阅读8分钟

Thread 创建线程实现 Runnable 接口 run 方法返回值为 void ,无法获取到线程的执行状态,执行结果。

public interface Runnable {
    public abstract void run();
}

线程池设计时考虑到可能需要获取任务的返回值,新增了一个 Callable 接口比 Runnable 多了返回值 V

public interface Callable<V> {
    V call() throws Exception;
}

由于任务是异步执行的,为了获取任务的执行结果,控制任务的执行 ,新增了一个接口 Future 用于获取任务的执行结果

public interface Future<V> {
    // 取消任务执行 ,mayInterruptIfRunning 为 true ,调用执行任务线程的 interrupt()方法
    boolean cancel(boolean mayInterruptIfRunning);
    // 任务是否被取消 
    boolean isCancelled();
    // 是否执行完成
    boolean isDone();
    // 获取执行结果,如果任务没有执行完成,会一直等待子任务完成 
    V get() throws InterruptedException, ExecutionException;
    // 获取执行结果,如果任务没有执行完成,会等待 timeout 时间,如果在 timeout 时间内没有完成会抛出 TimeoutException 异常  
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

Future 提供了 阻塞 或者 轮询 的方式得到任务的结果。

  • Future.get() 就是阻塞调用,在线程获取结果之前 get方法会一直阻塞。
  • Future提供了一个isDone方法,可以在程序中 轮询这个方法查询 执行结果。

以下是当一个Callable任务提交到线程池时,Future 是如何获取到 任务的执行结果的

// 当向线程池提交 Callable 时,会包装成为 RunnableFuture ,并且提交到线程池中执行 ,并返回
public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask); 
    return ftask;
}

// RunnableFuture 继承了 Runnable 和 Future 接口
public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

// newTaskFor 返回的是 FutureTask 
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

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

    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;
    
   
    private Callable<V> callable;

    private Object outcome; // non-volatile, protected by state reads/writes

    private volatile Thread runner;

    private volatile WaitNode waiters;
    
    // FutureTask 构造函数 ,FutureTask 有一个成员变量 state 记录了 任务的执行状态 
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;  // 初始化时 当前状态为 NEW 
    }
}

FutureTask 状态有 7 中 ,流转情况有以下 4 种

---
title: FutureTask 正常执行完成 
---
sequenceDiagram
    NEW->>COMPLETING: 
    COMPLETING ->> NORMAL: 
---
title: FutureTask 发生异常时   
---
sequenceDiagram
    NEW->>COMPLETING: 
    COMPLETING ->> EXCEPTIONAL: 
---
title: FutureTask 执行时被取消 
---
sequenceDiagram
    NEW->>CANCELLED: 
---
title: FutureTask 执行时调用中断方法
---
sequenceDiagram
    NEW->>INTERRUPTING: 
    INTERRUPTING ->> INTERRUPTED: 

需要注意,state 状态的改变是通过 CAS 操作的 ,上一个状态不匹配,状态是无法更新成功的

当 FutureTask 提交到线程池被执行时会调用 FutureTask 的 run 方法

public void run() {
    // 初始化状态为 NEW ,并记录 runner 为当前线程 
    if (state != NEW ||
        !RUNNER.compareAndSet(this, null, Thread.currentThread()))
        return;  // 如果有一个不成功说明状态异常(任务执行之前调用了 cancel()方法) ,直接返回  
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call(); // 调用 call 方法拿到执行结果 
                ran = true; // 如果 call 方法不发生异常则 ran 为 true 
            } catch (Throwable ex) { 
                result = null;  
                ran = false;
                setException(ex); // 发生异常 
            }
            if (ran) // 如果任务执行成功 
                set(result);
        }
    } finally {
        // 线程执行完成 runner 设置为 null 
        runner = null; 
        int s = state;
        if (s >= INTERRUPTING) // 状态如果为 INTERRUPTING ,需要等待状态 设置为 INTERRUPTED
            handlePossibleCancellationInterrupt(s);
    }
}


private void handlePossibleCancellationInterrupt(int s) {
    if (s == INTERRUPTING)
        while (state == INTERRUPTING) // 等待 INTERRUPTING 转化为 INTERRUPTED
            Thread.yield(); // 放弃线程执行,INTERRUPTING 设置为 INTERRUPTED 速度非常快 ,
}


// 正常执行 
protected void set(V v) {
     // 状态设置为 COMPLETING
    if (STATE.compareAndSet(this, NEW, COMPLETING)) {
        outcome = v;   // 存储任务执行结果 
        STATE.setRelease(this, NORMAL); // 最终状态 
        finishCompletion(); // 唤醒等待任务结果的线程 
    }
}

private void finishCompletion() {
    // assert state > COMPLETING;
    // WaitNode 是 一个链表结构,记录了等待当前线程执行任务完成而被阻塞的线程 
    // waiters 是头节点 ,如果头节点不为空,说明有其他线程调用了 get() ,等待任务完成
    // 当任务完成时,需要唤醒其他线程
    for (WaitNode q; (q = waiters) != null;) {
         // 把头节点的值赋值给临时变量 q ,头节点设置为 null 
        if (WAITERS.weakCompareAndSet(this, q, null)) {
            // for 循环遍历链表,唤醒每个等待任务执行结果的线程
            for (;;) {
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    LockSupport.unpark(t); // 唤醒线程 
                }
                WaitNode next = q.next;
                if (next == null) // next 为 null 说明到了结尾 退出循环 
                    break; 
                q.next = null; // unlink to help gc
                q = next;
            }
            break;
        }
    }

    done(); // 通知任务执行完成 

    callable = null;        // callable 设置为 null
}

static final class WaitNode {
    volatile Thread thread; //记录线程
    volatile WaitNode next; // 下一个节点
    WaitNode() { thread = Thread.currentThread(); }
}


// 当任务执行发生了异常 
protected void setException(Throwable t) {
    if (STATE.compareAndSet(this, NEW, COMPLETING)) {
        outcome = t;  // 存储发生的异常对象
        STATE.setRelease(this, EXCEPTIONAL); // 最终状态 
        finishCompletion(); // 唤醒等待任务结果的线程 
    }
}

// 取消任务 ,mayInterruptIfRunning 为 true 时 ,最终状态为 INTERRUPTED
// mayInterruptIfRunning 为 false 时 ,最终状态为 CANCELLED
// 执行过程中 如果 call 方法执行过程中被阻塞 ,比如调用了 wait() ,sleep()方法 。
// 另外一个线程调用了 cancel(true) , 虽然会抛出 InterruptedException 异常 ,
// 但是 state 已经设置为 INTERRUPTING ,setException() 方法中  CAS 会失败 ,最终状态为 CANCELLED
public boolean cancel(boolean mayInterruptIfRunning) {
     // 当状态不为 NEW 时,无法取消成功 
    if (!(state == NEW && STATE.compareAndSet
          (this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        return false;
    try {    // in case call to interrupt throws exception
        if (mayInterruptIfRunning) {
            try {
                Thread t = runner;
                if (t != null)
                    t.interrupt();  // 调用 interrupt 方法
            } finally { // final state
                STATE.setRelease(this, INTERRUPTED); // 设置最终状态 
            }
        }
    } finally {
        finishCompletion(); // 唤醒等待任务结果的线程 
    }
    return true; // 取消成功
}

// 无限时等待获取任务执行结果 
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING) // 如果状态为 NEW ,COMPLETING ,说明还没到最终状态 ,等待任务完成 
        s = awaitDone(false, 0L); // 无限时等待任务完成 
    return report(s); // 返回最终结果 
}

// 超时等待获取任务执行结果 
public V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException {
    if (unit == null)
        throw new NullPointerException();
    int s = state;
     // 如果状态为 NEW ,COMPLETING ,等待 timeout时间 ,如果 timeout 还未完成抛出TimeoutException 异常 
    if (s <= COMPLETING &&
        (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
        throw new TimeoutException();
    return report(s); // 返回最终结果 
}

// 等待超时
private int awaitDone(boolean timed, long nanos)
    throws InterruptedException {
    long startTime = 0L;    // Special value 0L means not yet parked
    WaitNode q = null;
    boolean queued = false;
    for (;;) {
        int s = state;
         // 状态大于 COMPLETING 说明任务已完成 ,直接返回 
        if (s > COMPLETING) {
            if (q != null)
                q.thread = null;
            return s;
        }
        // 状态等于 COMPLETING ,一个临界状态 ,很快就会有成功结果,或者抛 ExecutionException
        else if (s == COMPLETING)
            Thread.yield(); // 很快就能获取到结果交出执行权,下次调度时可能就有结果了  
            
        else if (Thread.interrupted()) {  // 如果当前线程被中断,移除当前的等待节点 ,抛出InterruptedException 异常 
            removeWaiter(q);
            throw new InterruptedException(); 
        }
        else if (q == null) {
            if (timed && nanos <= 0L) // 设置超时参数非法,直接返回 
                return s;
            q = new WaitNode(); // 新建节点
        }
        // q 赋值后 for 循环 走此分支 
        else if (!queued)
             // 之前的头节点 waiters 赋值为 q.next ,并且 q 设置为头节点,设置成功后 queued 为 true
            queued = WAITERS.weakCompareAndSet(this, q.next = waiters, q);
        else if (timed) { // 如果设置超时 
            final long parkNanos;
            if (startTime == 0L) { // 第一次 
                startTime = System.nanoTime(); // 赋值为当前时间 
                if (startTime == 0L)
                    startTime = 1L;
                parkNanos = nanos;
            } else { // 当超时时间到,但是任务还没完成时 for 循环 走此分支 
                long elapsed = System.nanoTime() - startTime;
                if (elapsed >= nanos) { // 阻塞时间大于等于 nanos
                    removeWaiter(q);  // 移除等待节点 
                    return state; // 返回状态
                }
                parkNanos = nanos - elapsed;
            }
            // nanoTime may be slow; recheck before parking
            if (state < COMPLETING)
                // 阻塞线程 parkNanos 时间 ,当超时时间到,但是任务还没完成时,线程会被唤醒 
                LockSupport.parkNanos(this, parkNanos);
        }
        else
            LockSupport.park(this); // 阻塞线程 
    }
}


private void removeWaiter(WaitNode node) {
    if (node != null) {
        node.thread = null;  // 要移除的 node 节点的 thread 置为 null 
        retry:
        for (;;) { 
            // waiters 为头节点 ,遍历链表 移除节点的 thread 为 null的节点 。
            // 当 waiters 为 null 时 ,当前链表没有数据,不需要移除 ,直接跳出当前循环 
            for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                s = q.next;
                if (q.thread != null)
                    pred = q; // 记录 thread 为 null 的上一个节点 
                else if (pred != null) {
                    pred.next = s; // pre.next 置为 s ,相当于移除 q 节点 
                    // 检查临界情况 ,处理另外一个线程把 pred.thread 置为 null的情况 ,进行重新遍历 
                    if (pred.thread == null) 
                        continue retry;
                }
                // q.thread 为 null,说明该节点需要被移除 ,pred 也为 null, 
                // 说明 q 节点是头节点 并且是临界条件被另外一个线程被标记删除  
                // 需要重新设置头节点为 s ,设置失败进行重新遍历 
                else if (!WAITERS.compareAndSet(this, q, s))
                    continue retry;
            }
            break; // 没有进行 retry ,遍历完退出无限循环 
        }
    }
}

// 返回结果 
private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL) // 如果正常执行,返回任务结果 
        return (V)x;
    if (s >= CANCELLED) // 如果被取消,直接抛出 CancellationException 异常 
        throw new CancellationException();
    // 任务执行过程中发生异常 ,抛出 CancellationException 异常 
    throw new ExecutionException((Throwable)x);
}

// 判断是否取消 
public boolean isCancelled() {
    return state >= CANCELLED;
}
// 是否完成 
public boolean isDone() {
    return state != NEW;
}

线程池也提供了提交 Runnable ,返回的是 Future<?> 类型 , 调用 get 返回得到的结果为 null

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null); // Runnable 返回结果为 null
    execute(ftask);
    return ftask;
}

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);  // 创建 FutureTask 对象 
}

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result); // 通过 Runnable 生成 Callable 对象
    this.state = NEW;       // ensure visibility of callable
}


public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}
// Callable 适配器
private static final class RunnableAdapter<T> implements Callable<T> {
    private final Runnable task;
    private final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();   // 运行 Runnable
        return result; //返回结果 
    }
    public String toString() {
        return super.toString() + "[Wrapped task = " + task + "]";
    }
}