FutureTask 的源码简介,深入原理

我们知道,子线程操作,一般使用的辅助类为 Runnable ,还有一个是 Callable,我们平时使用 Runnable 的比较多,但这两个有什么区别呢?我们先看看源码

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

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

很明显,一个有返回值,一个没有返回值。使用 Runnable ,在子线程耗时操作后,获得的值,一般用成员变量保存,或者通过观察者模式,或者Android中的Message 及 Handler来发送和接收数据;Callable 则 本身直接就可以返回这个数据,两个使用原理一样,仅仅是一个封装好了返回值,一个需要自己再去倒腾这个值。

我们知道FutureTask存在于 AsyncTask 中,AsyncTask 是一个异步类,我们发现, 里面有一行执行的代码, exec.execute(mFuture); exec是线程池,那么可以直接执行,继续看:FutureTask<V> implements RunnableFuture<V> ,看看 RunnableFuture 是什么,RunnableFuture<V> extends Runnable, Future<V>, 说明 FutureTask 是一个Runnable, Future中定
义了几个回调方法,下面会分析到。 看到这,会发现,怎么没 Callable ,不要急, mFuture 在创建的时候,会传进去一个WorkerRunnable, 而WorkerRunnable则是实现了一个接口,WorkerRunnable<Params, Result> implements Callable<Result> ,那么就是说,FutureTask 在创建时,就把 Callable 当做参数,传进构造方法了,我们看看 FutureTask的源码中构造方法

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


    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }

好,到了这一步,才开始了 FutureTask 的分析。 构造方法中都有 Callable ,两个参数的构造方法中,FutureTask(Runnable runnable, V result), result 则是一个真正的值,继续点进去, this.callable = Executors.callable(runnable, result);

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

    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();
            return result;
        }
    }

我们发现,从代码中,可以看出这个一个设计模式,RunnableAdapter 本身也实现了 Callable 接口,把真正的 Runnable task 又包装了一层,task.run(); 执行的是子线程中耗时操作,然而不管得到的是什么,一旦外部调用了Callable的call()方法,返回的值则是传进来的 result。继续看FutureTask代码

    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 是个 Runnable,一旦线程池或者子线程执行,优先执行 run()方法,那么,看看它的源码

    public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, 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 ||!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
我们知道, state 刚开始值为0,如果不等于0,说明已经被重新赋值了;后面的代码,很熟悉吧!我们看看 U 这个属性,

    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
    private static final long STATE;
    private static final long RUNNER;
    private static final long WAITERS;
    static {
        try {
            STATE = U.objectFieldOffset
                (FutureTask.class.getDeclaredField("state"));
            RUNNER = U.objectFieldOffset
                (FutureTask.class.getDeclaredField("runner"));
            WAITERS = U.objectFieldOffset
                (FutureTask.class.getDeclaredField("waiters"));
        } catch (ReflectiveOperationException e) {
            throw new Error(e);
        }
        Class<?> ensureLoaded = LockSupport.class;
    }
   
这是一个静态模版块,会优先执行。看过上一篇文章的童靴都会知道, U 的含义,它通过反射方法,找到成员变量 state 、 runner、 waiters 的地址值,然后通过原子操作,防止多线程并发带来的问题。

成员变量 state 和 runner 好理解,waiters 是一个内部类, 看看源码
    static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }
这是一个数据结构,单链表结构,内部有个成员变量,存储的是线程 Thread 。 

继续看run()的源码,U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread())),成员变量 runner 的值为null,把当前所在线程,赋值给 runner, 如果成功,则返回 true;如果 runner 不为null, 或者赋值失败,返回false,则说明已经赋过值了,不用重复操作。
    if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, 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);
            }
        }

继续看,非空判断和状态判断,然后就是 result = c.call(); 操作,看看上面的介绍和本身里面做耗时操作,返回值就是这么来的,比如网络请求后,拿到服务器返回的值,在此赋值给result, boolean ran; 是判断 Callable 中执行耗时操作是否有异常,是否成功的标识,如果异常了, result 会置空,ran = false; 然后执行 setException(ex);操作,看看代码 

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

第一行是把成员变量 state 的值由 0 变为 1,然后把异常赋值给outcome,赋值成功后,把 state 的值,由 1 变为 3,然后执行finishCompletion()方法,此方法是一个循环执行,上述说了个属性waiters,是一个单链表结构,循环执行。如果  result = c.call(); 代码中没有异常,正常执行,则在此逻辑执行后,会继续执行 if (ran){set(result)}; 代码,此刻
    protected void set(V v) {
        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
            outcome = v;
            U.putOrderedInt(this, STATE, NORMAL); // final state
            finishCompletion();
        }
    }
把 state 的值由 0 变为 1,然后把获取到的值 result 赋值给 outcome, 然后再把 state 的值由 1 变为 2,执行 finishCompletion() 方法,同上。主要的逻辑就上面这一点,其他的都是一些对外暴露的方法和细节逻辑,比如对外提供值,是否取消此操作成功等。

比如对外暴露值的 get() 方法,
    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= 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;
        if (s <= COMPLETING &&
            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            throw new TimeoutException();
        return report(s);
    }
此方法比着上面,多了一个时间限制,如果超过时间 限制,直接报异常;时间内得到值,把state进行赋值,并返回给 s ,进行下一步 report(s)

    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);
    }
如果执行完毕,则返回 outcome 值 ,如果在此过程中被执行 cancle 取消操作,那么就抛异常。

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

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

这两个方法,上面是根据 state 值判断是否取消成功, 下面是否开始执行。都是根据状态值判断,再看看 cancel(boolean mayInterruptIfRunning) 方法,参数的意思是如果执行了,是否允许中断;

    public boolean cancel(boolean mayInterruptIfRunning) {
        if (!(state == NEW &&
              U.compareAndSwapInt(this, STATE, 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
                    U.putOrderedInt(this, STATE, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
    }

老样子,第一行代码,也是一个校验,如果 state 值为 0, 根据 mayInterruptIfRunning是否为true 把 state 值由 0 变为 5 或者 4,如果都成功了,则继续执行下一步,否则,终止。返回失败,比如已经开始执行完了耗时操作,state 值已经变成了1 ,此时就不能取消了,直接返回false,表示失败;如果还没开始执行,或者执行了,但还没执行完,还在耗时操作之中,则根据 mayInterruptIfRunning 值,state 值由 0 变为 5 或者 4,此时,即使执行了run()方法,set(v)时也会有 if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING))这个校验,此时 state 为5 或者 4 ,就不会继续赋值了。 继续往下看, 如果 mayInterruptIfRunning 为true,则会获取到耗时操作的线程,如果该线程已经执行,说明线程存在,不为空,则把它强制终止,然后 会把  state 值由 5 变为 6,表示已经终止,5的意思是终止进行中。然后会执行 finishCompletion(); 方法,上面分析过了。

awaitDone()方法和 removeWaiter(WaitNode node) 方法,主要就是需要了解链表数据结构,里面就是执行循环,和 state 状态赋值比较,做一下操作。

猜你喜欢

转载自blog.csdn.net/Deaht_Huimie/article/details/87087247