FutureTask源码深入分析

来源:互联网 发布:sqlserver 循环语句 编辑:程序博客网 时间:2024/05/16 17:02

Futuretask继承自RunnableFuture接口,这个接口只有一个方法

void java.util.concurrent.RunnableFuture.run()

继承Runnable接口与Future接口, run方法执行成功会使得Future也执行完成,并可以访问执行结果
通过Future的get方法返回的执行结果类型。

在未被取消的情况下,给Future设置计算结果。


接下来讲解FutureTask:
可取消的异步计算。这个类提供Future的基本的实现,其中包含开始计算方法和结束计算方法,查询看是否完成的方法以及返回计算结果的方法。仅当计算完成的情况下才能获得计算结果。当计算完成后,计算不能被重启或者取消(除非使用 runAndReset 方法来启动任务)。
FutureTask用来封装了 Callable 和 Runnable 的对象。因为FutureTask实现了Runnable接口,所以FutureTask可以提交给Executor(线程池)来执行。
这个类不仅可以独立使用,而且它也提供了protected方法用来实现定制的任务类。
通过FutureTask的get方法返回的执行结果类型。

原文:

A cancellable asynchronous computation. This class provides a base
implementation of Future, with methods to start and cancel a
computation, query to see if the computation is complete, and retrieve
the result of the computation. The result can only be retrieved when
the computation has completed; the get methods will block if the
computation has not yet completed. Once the computation has completed,
the computation cannot be restarted or cancelled (unless the
computation is invoked using runAndReset). A FutureTask can be used to
wrap a Callable or Runnable object. Because FutureTask implements
Runnable, a FutureTask can be submitted to an Executor for execution.
In addition to serving as a standalone class, this class provides
protected functionality that may be useful when creating customized
task classes. Type Parameters: The result type returned by this
FutureTask’s get methods

* 修订纪录:这个类的同步控制与之前的做法不同了,之前版本依赖于AbstractQueuedSynchronizer,在cancel过程中通过保持中断状态影响用户。现在的同步设计依靠更新state字段通过CAS原语来跟踪完成的状态,还有通过简单的Treiber stack 来持有等待中的线程。*
类中的几个内部属性:

    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;

任务的状态 state, 起初是 NEW, 之后运行状态仅在调用 set, setException 和 cancel 方法时变为 terminal的状态。
在完成时,state可能在短暂的时间内为 COMPLETING(当 set 执行结果的时候)或者 INTERRUPTING(通过中断runner来完成cancel(true)方法), 从中间状态到最终状态的转化使用更为廉价的ordered/lazy 写方式,因为这些值是唯一的并且不能再改变。
可能的状态变化过程:

 NEW -> COMPLETING -> NORMAL* NEW -> COMPLETING -> EXCEPTIONAL NEW -> CANCELLED NEW -> INTERRUPTING -> INTERRUPTED*

内部的callable任务,在执行后为空

    private Callable<V> callable;

返回的执行结果,或者从get方法中抛出的异常,这个值是non-volatile, 通过来state 来实现同步。

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

执行callable任务的线程,运行为CAS操作

    private volatile Thread runner;

等待线程的 Treiber stack,请参考 Treiber stack

    private volatile WaitNode waiters;

// Unsafe mechanics

    private static final sun.misc.Unsafe UNSAFE;    private static final long stateOffset;    private static final long runnerOffset;    private static final long waitersOffset;    static {        try {            UNSAFE = sun.misc.Unsafe.getUnsafe();            Class<?> k = FutureTask.class;            stateOffset = UNSAFE.objectFieldOffset                (k.getDeclaredField("state"));            runnerOffset = UNSAFE.objectFieldOffset                (k.getDeclaredField("runner"));            waitersOffset = UNSAFE.objectFieldOffset                (k.getDeclaredField("waiters"));        } catch (Exception e) {            throw new Error(e);        }    }

这部分是jdk1.7增加的内容, 使用了依赖于底层操作系统相关的特性的类sun.misc.Unsafe UNSAFE,这个类仅允许在jdk内部使用,这个方法在调用时会判断类加载器,我们的代码是没有“受信任”的,当然如果你希望让你的代码变成受信任的通过配置也可以做到,这个类未开放源代码,因为可以直接操作内存,所以jdk不建议用户来使用这个类,当然在高性能调优时会使用,比如零拷贝技术等。

stateOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("state")); 

获得state 的内存中相对于FutureTask类对象首地址的偏移量。

runnerOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("runner"));

获得 runner 的内存中相对于FutureTask类对象首地址的偏移量。

waitersOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("waiters"));

获得 waiters 的内存中相对于FutureTask类对象首地址的偏移量。


下面是类中的方法:

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

构造方法创建FutureTask对象,执行Callable任务。
将callable 赋值给内部成员变量将callable, 然后state初始状态置为 NEW


public FutureTask(Runnable runnable, V result) {        this.callable = Executors.callable(runnable, result);        this.state = NEW;       // ensure visibility of callable    }
构造方法创建FutureTask对象,执行Runnable任务。改编后使得 get方法在执行成功后可以返回结果。

如果不希望返回结果可以使用这样的方式:

Future<?> f = new FutureTask<Void>(runnable, null)

Executors.callable(runnable, result)方法会返回一个RunnableAdapter(), 这是一个适配器对象,下面是源码:

public static <T> Callable<T> callable(Runnable task, T result) {        if (task == null)            throw new NullPointerException();        return new RunnableAdapter<T>(task, result);    }

RunnableAdapter:

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

由此看出,其实还是调用call()方法来执行,只不过call()方法里面调用 task.run() 而已。


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

这个方法很简单,当state 为CANCELLED、INTERRUPTING、INTERRUPTED状态时候返回成功。


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

当state 不是NEW 返回true ,表示任务结束。


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);        }    }
if (state != NEW ||            !UNSAFE.compareAndSwapObject(this, runnerOffset,                                         null, Thread.currentThread()))            return;

如果state 不是NEW,那么任务已经被执行了,直接返回。
或者后面代码意思是 如果runner不为null(期望值),直接返回,否则赋值为当前的线程。

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

这里直接 调用 result = c.call() 执行任务。成功后状态 ran = true;
如果出错,重点看下setException(ex);

protected void setException(Throwable t) {        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {            outcome = t;            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state            finishCompletion();        }    }

如果future没有 set 返回值 并且任务也没有被取消,让Future report 抛出来的异常。这个方法在内部当计算出错的时候调用。
使用原子方法NSAFE.compareAndSwapInt设置state 为 COMPLETING, 并且将异常t赋值给返回结果。
然后调用UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL)设置state 为 EXCEPTIONAL, 这里使用了内存屏蔽,高效的保证了state的可见性,替代了volatile。
然后调用了

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    }

这段代码表示如果等待的线程不为null,调用UNSAFE.compareAndSwapObject将当前的等待线程 waiters 置为null,
然后开始内层循环,Thread t = q.thread;取出stack的一个元素,

q.thread = null;LockSupport.unpark(t);

断开引用,唤醒线程t去执行(get方法获取返回结果时由于计算未完成导致的阻塞)。

WaitNode next = q.next;if (next == null)      break;q.next = null; // unlink to help gcq = next;

这句就是让stack栈顶元素出栈,不解释了,前面已经说明数据结构了。
当next为空,表明stack清空了,break结束。

我们回到run方法, 代码看到这里了:

if (ran)   set(result);

如果ran = true 表明执行成功, 则执行 set(result),这个方法作用:如果没有被set过值或者任务被cancel,就将result值置为执行结果。
代码如下:

    protected void set(V v) {        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {            outcome = v;            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state            finishCompletion();        }    }

调用UNSAFE.compareAndSwapInt将state从NEW 置为 COMPLETING, 然后outcome 置为执行结果v,
UNSAFE.putOrderedIntstate COMPLETING 置为 NORMAL。然后调用finishCompletion()做清理工作,该方法前文已讲述过了。

之后看下finally中的代码:
runner = null; 在任务执行中runner不能为空为了避免并发执行的问题,这里执行完成后可以置为null了。

 int s = state;            if (s >= INTERRUPTING)                handlePossibleCancellationInterrupt(s);

这里需要重新判断state状态防止中断问题导致内存泄漏,继续看handlePossibleCancellationInterrupt(s)方法:

    private void handlePossibleCancellationInterrupt(int s) {        // It is possible for our interrupter to stall before getting a        // chance to interrupt us.  Let's spin-wait patiently.        if (s == INTERRUPTING)            while (state == INTERRUPTING)                Thread.yield(); // wait out pending interrupt

保证任何cancel(true)导致的中断仅仅被传到 在run方法下和runAndReset方法下的线程。


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

执行计算但不设置返回结果,重置future到初始状态,如果计算遇到异常或者被cancel则方法调用失败。它可以用来执行那种需要多次执行的任务。
如果运行成功并且重置状态完成,返回true
这个方法和run()差别仅在 没有了set(result); 这个设置返回值的部分,而且状态state不改变。


public V get() throws InterruptedException, ExecutionException {        int s = state;        if (s <= COMPLETING)            s = awaitDone(false, 0L);        return report(s);    }

这个方法为获取返回值,而且必要时会一直等待。
如果 state 为 NEW 或者 COMPLETING ,则执行awaitDone(false, 0L),该方法实现如下:

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

等待任务执行完成或者被终止。 参数timed表示是否需要计时,nanos表示等待的纳秒数。

if (Thread.interrupted()) {                removeWaiter(q);                throw new InterruptedException();            }

如果线程已经被中断,清除等待线程stack,然后抛出InterruptedException。
如果 s == COMPLETING ,表明任务执行完成在收尾工作,然后让出工作线程。

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

这些代码表示通过原语级别的锁阻塞当前线程,等待任务完成,一直到finishCompletion方法调用后才唤醒,
对于LockSupport.parkNanos(this, nanos);表示等待nanos 长时间后自动唤醒。
特别说下removeWaiter方法,这个方法是为了断开那些任务中断或者超时的等待返回结果的线程,就是将这些Node从stack中剔除
具体方法如下:

private void removeWaiter(WaitNode node) {        if (node != null) {            node.thread = null;            retry:            for (;;) {          // restart on removeWaiter race                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {                    s = q.next;                    if (q.thread != null)                        pred = q;                    else if (pred != null) {                        pred.next = s;                        if (pred.thread == null) // check for race                            continue retry;                    }                    else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,                                                          q, s))                        continue retry;                }                break;            }        }    }

这段比较难懂,看了半天。 算法描述:
首先将Node中的属性 thread 置null, 然后遍历等待线程的栈 waiters ,其中q 为当前节点, s为后继节点, pred为前驱节点。
当遇到当前节点 q 的 属性thread = null ,表示将要移除的节点,然后将后继节点直接接到前驱节点。然后判断前驱节点的属性 thread 是否为null, 也就是是否也是需要移除的节点,如果是的话跳出内循环重试。
如果移除的节点为栈顶元素,也就是头节点,那么调用UNSAFE.compareAndSwapObject方法将后继节点s赋值给q,作为头节点。

回到get()方法中,awaitDone结束之后,调用 report 方法来设置返回值。

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

这里根据返回值类型V来转化返回值, 当任务执行发生异常时,在get方法时候才抛出来,这样就知道了任务执行的情况了。


后看下cancel方法:

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                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);                }            }        } finally {            finishCompletion();        }        return true;    }

根据前面的叙述,这个比较简单,就是在可以中断的情况下将执行线程中断,并且state 状态置为 INTERRUPTED

0 0