【源码粗读】 - FutureTask

228 阅读3分钟

这是我参与8月更文挑战的第31天,活动详情查看:8月更文挑战

一般来说,Future我们是用于接收一个与异步任务返回的结果的。

Future接口的方法如下:

  boolean cancel(boolean mayInterruptIfRunning);
 boolean isCancelled();
     boolean isDone();
     V get() throws InterruptedException, ExecutionException;
   V get(long timeout, TimeUnit unit)
         throws InterruptedException, ExecutionException, TimeoutException;

如果是使用线程池,那么我们提交线程的过程一般会通过submit(runnable) 方法,这个方法在

 AbstractExecutorService

类中,方法如下:

 public Future<?> submit(Runnable task) {
     if (task == null) throw new NullPointerException();
     RunnableFuture<Void> ftask = newTaskFor(task, null);
     execute(ftask);
     return ftask;
 }
 ​
     protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
         return new FutureTask<T>(runnable, value);
     }

在这里我们会发现,实际上提交到线程池中,线程的运行和普通无结果的异步任务是相同的,那么区别就在这个

FutureTask中了。

我们来看看FutureTask的源码:

 public class FutureTask<V> implements RunnableFuture<V> {
     //...    
 }
 //实际上这个接口只规定了一个run方法:
 //public interface RunnableFuture<V> extends Runnable, Future<V> {
     /**
      * Sets this Future to the result of its computation
      * unless it has been cancelled.
      */
     //void run();
 //}
 ​

查看一下内部的变量:

 //这里可以看到,future也提供了一套和thread中类似的线程状态值
 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;
    //这个就是我们的结果了,注释里写的也很有意思:这个变量的可见性是通过state值的volatile间接保证的
     private Object outcome; // non-volatile, protected by state reads/writes
    //下面两个后面再说
     private volatile Thread runner;
     
     private volatile WaitNode waiters;

回顾一下我们之前使用Future的方式:

  • 任务提交到线程池,并获取future对象
  • 调用future.get()

那么我们就分两步,来看一下future对应是如何工作的。

1.提交

提交到线程池就不再赘述了,简要提一下我们提交的时候调用的方法是构造方法

 public FutureTask(Callable<V> callable) {
     if (callable == null)
         throw new NullPointerException();
     this.callable = callable;
     this.state = NEW;       // ensure visibility of callable
 }

然后根据上面线程池抽象类提供的信息,我们就直接将这个作为任务塞到线程池中去运行了,根据之前看线程池的经验,我们这时候看看这个的run方法:

 public void run() {
     if (state != NEW ||
         !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                      null, Thread.currentThread()))
         return;
     try {
         Callable<V> c = callable;
         if (c != null && state == NEW) {
             V result;
             boolean ran;
             try {
                 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
         int s = state;
         if (s >= INTERRUPTING)
             handlePossibleCancellationInterrupt(s);
     }
 }

这里能看到,实际上我们任务塞到线程池并执行完毕,其实是这样子的流程:

  • 任务组装成futureTask
  • futureTask被分派到线程池中等待执行
  • 执行完毕,结果储存在futureTask对象中

2.获取

 public V get() throws InterruptedException, ExecutionException {
     int s = state;
     if (s <= COMPLETING)
         s = awaitDone(false, 0L);
     return report(s);
 }
 ​
  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;
             if (s > COMPLETING) {
                 if (q != null)
                     q.thread = null;
                 return s;
             }
             else if (s == COMPLETING) // cannot time out yet
                 Thread.yield();
             else if (q == null)
                 q = new WaitNode();
             else if (!queued)
                 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);
         }
     }
 ​
     private V report(int s) throws ExecutionException {
         Object x = outcome;
         if (s == NORMAL)
             return (V)x;
         if (s >= CANCELLED)
             throw new CancellationException();
         throw new ExecutionException((Throwable)x);
     }

futureTask中的精华,一部分就在awaitDone里面了。

  • 维护了一个等待队列(waitNode)并返回当前的处理状态
  • 使用CAS来保证状态值的原子性。