ExecutorService的未来任务并未真正取消

时间:2012-06-22 14:42:26

标签: java concurrency executorservice future

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

我在哪里错了?这样做有好处吗?

2 个答案:

答案 0 :(得分:16)

  

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

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

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

有关详细信息,请参阅我的答案:

  

how to suspend thread using thread's id?

答案 1 :(得分:0)

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

JavaDocinterrupt

进行了以下说明
  

public void interrupt()

  中断此线程。除非目前   线程正在打断自己,这总是被允许的   调用此线程的checkAccess方法,这可能会导致   抛出SecurityException。

     

如果在调用wait()时阻塞了这个线程,请等待(long),   或者等待(long,int)Object类或join()的方法,   join(long),join(long,int),sleep(long)或sleep(long,int)方法   这个类,然后它的中断状态将被清除   收到InterruptedException。

     

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

     

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

     

如果以前的条件都没有,则该线程会中断   状态将被设置。

     

中断非活动的线程无需任何效果。

     

抛出:SecurityException - 如果当前线程无法修改它   螺纹

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