首页 > 解决方案 > FutureTask 实现重新读取状态以防止泄漏中断

问题描述

FutureTask以下是Java中一些方法的实现:

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

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

handlePossibleCancellationInterrupt方法:

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

    // 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 方法在cancel方法完成中断线程之前完成,并且状态已更改为interruptinginterrupted但我无法理解两件事:

为什么运行方法中有这些代码行:

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

无法更改为此:

if (state == INTERRUPTING)
    handlePossibleCancellationInterrupt(state);

所以我无法理解两件事:

  1. 这个声明的作用是什么int s = state
  2. 为什么state >= INTERRUPTING语句不能改成这个state == INTERRUPTING

标签: java

解决方案


1.效果int s = state

state作为一个volatile变量,必须是将其分配给 的主要原因s。这样,我们可以避免if语句中额外的昂贵的易失性读取访问。

此处此处的链接讨论了易失性读取性能。

2.state >= INTERRUPTING

可能最初有讨论重置interrupted线程的状态handlePossibleCancellationInterrupt()

下面的块评论在handlePossibleCancellationInterrupt()

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

清除中断应该已经发生,即使状态是INTERRUPTED.


推荐阅读