FutureTask 代表一个可取消的异步计算。它实现了 RunnableFuture 接口,RunnableFuture 接口继承了 Runnable 接口和 Future 接口。

Java Future模式自定义实现_System

Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果,还提供了取消任务的方法。

Java Future模式自定义实现_线程池_02

FutureTask 因此既可以获取到异步计算的结果,又可以当做一个任务提交到线程池。

FutureTask<String> future =
  new FutureTask<String>(new Callable<String>() {
    public String call() {
      return searcher.search(target);
  }});
executor.execute(future);

获取异步计算的结果有两种方式

/**
 * 如果有必要,等待任务执行完毕,并返回计算结果.
 *
 * @return 计算的结果
 * @throws CancellationException 计算被取消
 * @throws ExecutionException  计算自己出现异常
 * @throws InterruptedException  当前线程在等待时被中断
 */
V get() throws InterruptedException, ExecutionException;

/**
 * 如果有必要,最多等待给定的时间去执行任务完毕,并返回计算结果(如果结果可用).
 */
V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

get 方法是如何做到,如果任务没执行完就阻塞的呢?
FutureTask 内部定义了多个执行状态,按照状态来控制获取是否阻塞。JDK1.6 使用的 AQS 实现。

public class FutureTask<V> implements RunnableFuture<V> {
    /**
     * Possible state transitions:
     * NEW -> COMPLETING -> NORMAL			 //正常结束
     * NEW -> COMPLETING -> EXCEPTIONAL		 //执行报错
     * NEW -> CANCELLED						 //调用了 cancel(fasle) 
     * NEW -> INTERRUPTING -> INTERRUPTED    //调用了 cancel(true) 
     * 从中间状态过渡到最终状态后,无法更进一步修改
     */
    private volatile int state;
    private static final int NEW          = 0; //初始为NEW
    private static final int COMPLETING   = 1; //中间状态,当 outcome 执行前就会是此状态
    private static final int NORMAL       = 2; //任务正常执行完毕
    private static final int EXCEPTIONAL  = 3; //任务执行异常
    private static final int CANCELLED    = 4; //任务被取消了
    private static final int INTERRUPTING = 5; //中间状态,只在调用 cancel(true) 才临时出现
    private static final int INTERRUPTED  = 6; //任务被中断了

    /** The underlying callable; nulled out after running */
    //需要执行的任务
    private Callable<V> callable;
    /** The result to return or exception to throw from get() */
    //保存计算结果
    private Object outcome; // non-volatile, protected by state reads/writes
    /** The thread running the callable; CASed during run() */
    //当前线程
    private volatile Thread runner;
    /** Treiber stack of waiting threads */
    //等待此计算任务结束获取结果的线程
    private volatile WaitNode waiters;
    
    static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }
}

一个简单的示例

/**
 * Created by Tangwz on 2019/7/14
 */
public class TestFutureTask {
    public static void main(String[] args) {
        MyTask myTask = new MyTask();
        FutureTask<String> futureTask = new FutureTask<>(myTask);
        //不用线程池,也可单独使用线程
//        Thread thread = new Thread(futureTask);
//        thread.start();
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(futureTask);
        //取消任务
//        futureTask.cancel(true);
        //突然关闭线程池
//        executorService.shutdownNow();
        try {
        	//此方法会阻塞,等待返回结果
            String result = futureTask.get();
            System.out.println("任务结果:" + result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }

    static class MyTask implements Callable<String> {
        @Override
        public String call() throws InterruptedException {
            System.out.println("模拟任务执行 1s");
            Thread.sleep(1000);
            return "success";
        }
    }
}

输出结果:

模拟任务执行 1s
任务结果:success

构造一个 FutureTask 还可以通过一个 Runnable,并指定一个结果。

public FutureTask(Runnable runnable, V result) {
	//使用了适配器模式
    this.callable = Executors.callable(runnable, result);
    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);
}

/**
 * A callable that runs given task and returns given result
 */
static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

构造一个 FutureTask 后,调用 futureTask.get() 就会阻塞调用的线程直到任务执行完毕,让我们来看看 get 方法内部是怎样的。直接获取结果和设置了超时时间的获取差别不大,后者会多抛一个超时异常。

/**
 * @throws CancellationException {@inheritDoc}
 */
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
    	//正在执行中就等待执行完毕
        s = awaitDone(false, 0L);
    //若已经结束了,按照状态返回结果
    return report(s);
}

/**
 * @throws CancellationException {@inheritDoc}
 */
public V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException {
    if (unit == null)
        throw new NullPointerException();
    int s = state;
    if (s <= COMPLETING &&
    	//若超时时计算任务还没结束,抛出超时异常
        (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
        throw new TimeoutException();
    //若已经结束了,按照状态返回结果
    return report(s);
}

/**
 * Awaits completion or aborts on interrupt or timeout.
 *
 * @param timed true if use timed waits
 * @param nanos time to wait, if timed
 * @return state upon completion
 */
//等待执行完毕,或者被中断/超时
private int awaitDone(boolean timed, long nanos)
    throws InterruptedException {
    //此查询计算结果的任务应该结束的时间点
    final long deadline = timed ? System.nanoTime() + nanos : 0L;
    WaitNode q = null;
    //是否入队列
    boolean queued = false;
    for (;;) {
    	//若此任务被中断,移除队列中的节点,表明此线程不能再等待计算结果了
        if (Thread.interrupted()) {
            removeWaiter(q);
            throw new InterruptedException();
        }
        //获取此时的计算状态
        int s = state;
        //按照状态的实际规则,状态大于 COMPLETING 代表计算结果已经放到 outcome 中
        //这时可以返回状态获取结果了
        if (s > COMPLETING) {
        	//若此线程的等待节点不为空,移除节点中的线程属性
            if (q != null)
                q.thread = null;
            return s;
        }
        //若正在执行中,暂时放弃CPU资源,稍等一会儿
        else if (s == COMPLETING) // cannot time out yet
            Thread.yield();
        //到这里说明计算任务还没开始,创建一个等待节点
        else if (q == null)
            q = new WaitNode();
        //没有入队列,就加入到队列中
        else if (!queued)
        	//CAS操作,失败上面还有循环,不会退出,再次设置
            queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                 q.next = waiters, q);
        //是否设置了超时时间
        else if (timed) {
            nanos = deadline - System.nanoTime();
            //是否已经超时
            if (nanos <= 0L) {
            	//移除此节点
                removeWaiter(q);
                //因为此查询任务已超时,不管计算任务是什么状态,直接返回此时的状态
                return state;
            }
            //阻塞一定的时间,直到被唤醒或者中断或者超时
            LockSupport.parkNanos(this, nanos);
        }
        else
        	//阻塞,直到被唤醒或者中断
            LockSupport.park(this);
    }
}

按照状态来返回结果

/**
 * Returns result or throws exception for completed task.
 *
 * @param s completed state value
 */
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL)
    	//正常结束状态,返回结果
        return (V)x;
    //如果被取消或者被中断,抛出被取消异常
    if (s >= CANCELLED)
        throw new CancellationException();
    //s == EXCEPTIONAL,代表执行任务报错
    throw new ExecutionException((Throwable)x);
}

任务有没有执行完?是什么时候修改的 state 呢?
关键点就在 FutureTask 重写了的 run 方法,线程运行时就会调用 FutureTask.run。

/**
 * Sets this Future to the result of its computation
 * unless it has been cancelled.
 */
//如果任务没有被取消,设置 Future 为计算的结果
public void run() {
	//若此任务状态不为初始值,或者设置执行线程时失败
	//都表示此任务被其他线程执行了,可以直接返回
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    try {
    	//执行初始化 Future 的时候传递的 Callable
        Callable<V> c = callable;
        //不为空,且为初始状态才执行
        if (c != null && state == NEW) {
            V result;
            //表明任务是否执行完毕
            boolean ran;
            try {
            	//真正的调用 run 或者 call 方法的地点
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
            	//捕获了执行任务抛出的异常
                result = null;
                ran = false;
                //设置执行任务抛异常的结果
                setException(ex);
            }
            if (ran)
            	//设置正常执行任务的结果
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        //利用了 volatile 的禁止指令重排,保证中断后读到的 runner 为空
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

按照任务执行的情况来设置结果

//计算任务执行抛异常设置异常结果
protected void setException(Throwable t) {
	//任务可能被取消,CAS 操作
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = t;
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        //CAS 成功后,结束任务,唤醒所有等待结果的线程
        finishCompletion();
    }
}

//计算任务执行正常结束设置结果
protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

/**
 * Removes and signals all waiting threads, invokes done(), and
 * nulls out callable.
 */
private void finishCompletion() {
    // assert state > COMPLETING;
    //这里循环因为唤醒期间可能存在新的查询任务进来
    for (WaitNode q; (q = waiters) != null;) {
        if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
        	//循环唤醒所有等待线程
            for (;;) {
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    LockSupport.unpark(t);
                }
                WaitNode next = q.next;
                if (next == null)
                    break;
                q.next = null; // unlink to help gc
                q = next;
            }
            break;
        }
    }
    //可扩展的方法,默认无实现
    done();

    callable = null;        // to reduce footprint
}

如何取消任务?调用 futureTask.cancel(true) 方法。

/**
 * 试图取消此任务的执行。如果任务已经完成或者已取消,或者其他原因导致无法取消,cancel 返回 false;
 * 当任务还没启动,调用 cancel 成功那么此任务永远不会执行(run 方法会检查状态);
 * 当任务已经启动还未完成时,mayInterruptIfRunning 决定是否停止正在执行的任务
 * @param mayInterruptIfRunning 执行中的任务是否允许中断
 */
public boolean cancel(boolean mayInterruptIfRunning) {
    if (!(state == NEW &&
          UNSAFE.compareAndSwapInt(this, stateOffset, 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();
            } finally { // final state
            	//任务状态最终设置成 INTERRUPTED
                UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
            }
        }
    } finally {
        finishCompletion();
    }
    return true;
}

判断任务有无执行完成,有无被取消,就很简单

public boolean isCancelled() {
    return state >= CANCELLED;
}

public boolean isDone() {
    return state != NEW;
}

还有一个特殊的方法 runAndReset,执行任务但是不设置计算结果,如果执行期间任务遇到错误或者被取消,那么该方法返回失败。此方法被设计用于那些本质上要执行多次的任务。

/**
 * Executes the computation without setting its result, and then
 * resets this future to initial state, failing to do so if the
 * computation encounters an exception or is cancelled.  This is
 * designed for use with tasks that intrinsically execute more
 * than once.
 *
 * @return {@code true} if successfully run and reset
 */
protected boolean runAndReset() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return false;
    boolean ran = false;
    int s = state;
    try {
        Callable<V> c = callable;
        if (c != null && s == NEW) {
            try {
            	//不获取执行结果,不设置结果到 outcome 中
                c.call(); // don't set result
                ran = true;
            } catch (Throwable ex) {
                setException(ex);
            }
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
    return ran && s == NEW;
}