执行者服务的未来任务不会真正取消



我将我的期货从执行器服务推送到哈希映射中。 稍后,我可能会从哈希图中调用期货取消。 虽然结果是正确的,但我后来在 Callable 过程中命中了断点,好像 Future cancel() 没有效果一样。 我认为这里可能是两个不同引用的情况(即使引用 ID 在断点时被列为相同),但想知道一些专家是否可以插话。 代码如下所示:

ExecutorService taskExecutor = Executors.newCachedThreadPool();
Map <String, Future<Object>> results = new HashMap <String, Future<Object>>();      
Future<Object> future = taskExecutor.submit(new MyProcessor(uid));
results.put(uid, future);

允许处理继续(这是一个在传入任务时提交任务的循环),稍后我可能会尝试通过调用此方法从外部源取消:

public static synchronized boolean cancelThread(String uid) {
    Future<Object> future = results.get(uid);
    boolean success = false;
    if (future != null) {
        success = (future.isDone() ? true : future.cancel(true));
        if (success)
            results.remove(uid);
    }
    return success;     
}

但是在调用 future.cancel() 之后,我仍然在 MyProcessor.call() 中遇到一个"非取消"路径 - 即它并没有真正被取消。

我哪里出错了? 有没有更好的办法?

后来我在 Callable 过程中命中了断点,好像 Future cancel() 没有效果一样。

Future.cancel(true)删除队列中尚未运行的作业,但如果作业已在运行,则等效于在运行该作业的线程上执行Thread.interrupt()。 这会在线程上设置中断位,并导致任何sleep()wait()和其他一些方法抛出InterruptedException

重要的是要意识到它不会停止线程。 您需要主动检查线程循环中的中断标志或正确处理InterruptedException

有关更多详细信息,请参阅我的SO答案:如何使用线程的ID挂起线程?

FutureTask :: boolean cancel(boolean mayInterruptIfRunning)将在当前正在运行的线程上执行interrupt

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

JavaDoc 在下面说interrupt

公共无效中断()

中断此线程。除非电流 线程正在中断自身,这始终是允许的, 调用此线程的 checkAccess 方法,这可能会导致 要抛出的安全异常。

如果此线程在调用 wait(), wait(long) 时被阻塞, 或 Object(或 join() 的 wait(long, int) 方法, join(long), join(long, int), sleep(long), or sleep(long, int), 方法 的此类,则其中断状态将被清除,它将 收到中断异常。

如果此线程在可中断的 I/O 操作中被阻塞 通道然后通道将被关闭,线程的中断状态 将被设置,并且线程将收到 ClosedByInterruptException。

如果此线程在选择器中被阻塞,则线程的中断 状态将被设置,它将立即从选择中返回 操作,可能具有非零值,就像选择器的 已调用唤醒方法。

如果上述条件均不成立,则此线程的中断 将设置状态。

中断不活动的线程不需要有任何效果。

抛出:安全异常 - 如果当前线程无法修改此 线

总而言之,取消FutureTask只有在线程被阻塞时才有影响(在 wait(),... 的调用中),否则开发人员有责任在执行非阻塞操作时检查Thread.currentThread().isInterrupted()退出。

相关内容

  • 没有找到相关文章

最新更新