Future、Callable和FutureTask

你离开我真会死。 提交于 2020-03-17 11:56:28

某厂面试归来,发现自己落伍了!>>>

一、为什么使用Future

    jdk提供了Thread和Runnale支持多线程,但是这两种方式执行完任务之后都没有办法获取到执行结果。

    jdk1.5之后提供了Future和Callable来解决这个问题,Future方式提供了异步获取执行结果的方式,避免开启任务之后阻塞等待返回结果,而是开启任务之后可以干其他事情异步获取结果。

 

二、FutureTask

    FutureTask实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable和Future接口,所以FutureTask可以作为Runnable被线程执行,也可以通过Callable异步获取任务执行结果。

 

三、FutureTask源码分析

    1.构造方法        

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
}

        提供了两种构造方法,第二种和第一种的区别在于,第二种执行结果是通过result直接设置进去的,而第一种是通过callable获取的。

 

    2.FutureTask的状态,可以看到有几种状态的定义,以及状态之间的转换。

/**
 * The run state of this task, initially NEW.  The run state
 * transitions to a terminal state only in methods set,
 * setException, and cancel.  During completion, state may take on
 * transient values of COMPLETING (while outcome is being set) or
 * INTERRUPTING (only while interrupting the runner to satisfy a
 * cancel(true)). Transitions from these intermediate to final
 * states use cheaper ordered/lazy writes because values are unique
 * and cannot be further modified.
 *
 * Possible state transitions:
 * NEW -> COMPLETING -> NORMAL
 * NEW -> COMPLETING -> EXCEPTIONAL
 * NEW -> CANCELLED
 * NEW -> INTERRUPTING -> INTERRUPTED
 */
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;

 

    3.其他属性    

// 任务
private Callable<V> callable;
// 执行结果
private Object outcome; // non-volatile, protected by state reads/writes
// 执行任务的线程,用来取消或者中断任务使用
private volatile Thread runner;
// 等待线程,get方法获取执行结果的时候,那么这些线程形成的栈的头部节点就是waiters
private volatile WaitNode waiters;

static final class WaitNode {
    volatile Thread thread;
    volatile WaitNode next;
    WaitNode() { thread = Thread.currentThread(); }
}

 

    4.CAS辅助工具

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

 

    4.使用FutureTask示例

FutureTask<Integer> task = new FutureTask<>(()-> {
    Thread.sleep(10000L);
    return 1;
});
new Thread(task).start();
Integer result = task.get();

 

    5.启动任务,从run方法开始

public void run() {
    // 如果状态不是NEW,并且runner已经执行过了(runner旧的值不为null),返回
    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 {
                // 执行callable得到结果
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result); // 将执行的结果设置给outcome
        }
    } 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);
    }
}

protected void setException(Throwable t) {
    // 抛出异常
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = t;
        // 此处用putOrderedInt而不是CAS,是多线程环境下,可能被其他线程改变了,所以是为了保证状态改为EXCEPTIONAL
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        finishCompletion();
    }
}

protected void set(V v) {
    // 执行成功
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;
        // 此处用putOrderedInt而不是CAS,是多线程环境下,可能被其他线程改变了,所以是为了保证状态改为NORMAL
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

private void finishCompletion() {
    // assert state > COMPLETING;
    // 自旋,直到将waiters清空,并且唤醒waiters栈中所有节点线程
    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
}

// 此时状态可能为INTERRUPTING和INTERRUPTED,因为任务可能被其他线程给取消了,此种情况下我们无法判断,所以只能等待任务状态到终止状态
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) // 挂起线程直到状态修改为INTERRUPTED
            Thread.yield(); // wait out pending interrupt

    // assert state == INTERRUPTED;

    // We want to clear any interrupt we may have received from
    // cancel(true).  However, it is permissible to use interrupts
    // as an independent mechanism for a task to communicate with
    // its caller, and there is no way to clear only the
    // cancellation interrupt.
    //
    // Thread.interrupted();
}

    由上述源码分析,run()主要做了以下几件事情

    (1).将runner属性设置成当前正在执行run方法的线程

    (2).调用callable的call方法执行任务

    (3).设置执行结果,若执行成功,将执行结果保存在outcome中;若发生异常,则将异常保存到outcome中,设置结果之前,CAS将状态设置为COMPLETING,设置结果之后,将状态设置为终止态,NORMAL或者EXCEPTIONAL,再将callable设置为null;

    (4).唤醒所有的结果查询等待线程,并将waiters清空,将runner设置为null

    (5).如果有其他线程取消任务(中断情况),自旋等待中断完成

 

    6.get()获取任务执行结果

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); // 如果执行任务的线程interrupted,将等待获取结果的线程都移除掉(移除的过程中会唤醒所有的等待线程),然后抛出InterruptedException
            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表示是否成功入栈(因为多线程有竞争)
            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); // 不带超时的线程挂起
    }
}

// 移除等待的线程节点,先将当前节点的thread设置为null,为后续剔除节点做了标记
// 1.如果当前节点在栈顶,那么此时q和pred肯定为null,直接CAS尝试将栈顶设置为下一个节点;如果设置成功,这个地方仍然会再次执行循环,将其他node.thread==null的节点也剔除
// 2.要移除的节点不再栈顶,我们会遍历栈,直到找到node.thread==null的节点,我们将node的前驱节点的next指向node的下一个节点,就将节点剔除掉了。因为存在多线程竞争的情况,pred.thread==null表示该节点被其他线程标记了,下面的节点都是基于该节点,继续遍历没有意义,所以直接从头开始遍历。
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;
        }
    }
}

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); // 任务执行异常
}

    awaitDown和get方法都没有加锁,state和waiters属性都有加volatile关键字,而对waiters的修改都是使用CAS,保证了线程安全。

 

    7.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) {
            // 取消任务,并将状态设置为INTERRUPTED
            try {
                Thread t = runner;
                if (t != null)
                    t.interrupt();
            } finally { // final state
                UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
            }
        }
    } finally {
        // 取消任务之后,将获取结果的等待线程都清空
        finishCompletion();
    }
    return true;
}

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
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!