14

我将我的 Futures 从 ExecutorService 推送到哈希映射中。稍后,我可能会从哈希映射中调用 Futures 的取消。虽然结果是真的,但我后来在 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() 中遇到“未取消”路径 - 即它并没有真正被取消。

我哪里错了?有更好的方法吗?

4

2 回答 2

23

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

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

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

See my SO answer here for more details: How to suspend thread using thread's id?

于 2012-06-22T14:45:31.823 回答
1

FutureTask :: boolean cancel(boolean mayInterruptIfRunning) will perform interrupt on current running thread.

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 says the below for interrupt

public void interrupt()

Interrupts this thread. Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.

If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.

If none of the previous conditions hold then this thread's interrupt status will be set.

Interrupting a thread that is not alive need not have any effect.

Throws: SecurityException - if the current thread cannot modify this thread

To conclude; cancel of FutureTask has only impact if the thread is blocked (in an invocation of the wait(),...) else it is developer responsibility to check Thread.currentThread().isInterrupted() to quit; while performing non blocked operation.

于 2016-05-12T11:13:56.227 回答