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

我将Futures从ExecutorService推送到哈希映射中。 之后,我可以在哈希映射中调用取消期货。 虽然结果是正确的,但后来我在Callable过程中命中了断点,好像Future cancel()没有效果。 我认为这可能是两个不同引用的情况(即使引用ID在断点时被列为相同),但是想知道某些专家是否可以插入。这是代码的样子:

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

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

 public static synchronized boolean cancelThread(String uid) { Future 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

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

如何使用线程的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

public void interrupt()

中断此线程。 除非当前线程正在中断自身(始终允许),否则将调用此线程的checkAccess方法,这可能导致抛出SecurityException。

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

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

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

如果以前的条件都不成立,则将设置该线程的中断状态。

中断不活动的线程不会产生任何影响。

抛出:SecurityException – 如果当前线程无法修改此线程

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