如何立即停止使用ExecutorService启动的任务?

我已经尝试了许多不同的方法来立即停止使用ExecutorService启动的任务,但没有运气。

Future future = executorService.submit(new Callable( public Void call () { ... do many other things here.. if(Thread.currentThread.isInterrupted()) { return null; } ... do many other things here.. if(Thread.currentThread.isInterrupted()) { return null; } } )); if(flag) { // may be true and directly cancel the task future.cancel(true); } 

有时候我需要在启动后立即取消任务,你可能会好奇我为什么要这样做,你可能会想象一个用户不小心点击“下载”按钮启动“下载任务”并且他立即想要取消操作,因为它只是偶然的点击。

问题是在调用future.cancel(true)之后 ,任务没有停止, Thread.currentThread.isInterrupted()仍然返回false ,我无法知道任务是从call()方法内部停止的。

我想在调用future.cancel(true)并在call()方法中不断检查该标志后设置一个像cancelled = true的标志,我认为这是一个hack而且代码可能非常难看,因为用户可以启动很多在同一时刻的任务。

是否有更优雅的方式来实现我想要的?

编辑:

这真让我疯了。 我现在花了差不多一天时间解决这个问题。 我将尝试解释一下我面临的问题。

我执行以下操作来启动5个任务,每个任务将启动5个线程来下载文件。 然后我立即停止所有5个任务。 对于下面的所有方法调用,我启动一个线程(ExecutorService.submit(task))使其异步,你可以从方法的后缀中看出来。

 int t1 = startTaskAysnc(task1); int t2 = startTaskAysnc(task2); int t3 = startTaskAysnc(task3); int t4 = startTaskAysnc(task4); int t5 = startTaskAysnc(task5); int stopTaskAysnc(t1); int stopTaskAysnc(t2); int stopTaskAysnc(t3); int stopTaskAysnc(t4); int stopTaskAysnc(t5); 

startTaskAysnc()中 ,我只是启动到远程服务器的套接字连接以获取文件的大小(这肯定需要一些时间),在成功获取fileSize之后,我将启动5个线程来下载文件的不同部分。 如下所示(代码被简化以使其更容易理解):

 public void startTaskAsync(DownloadTask task) { Future future = executorService.submit(new Callable( public Void call () { // this is a synchronous call int fileSize = getFileSize(); System.out.println(Thread.currentThread.isInterrupted()); .... Future futures = new Future[5]; for (int i = 0; i < futures.length; ++i) { futures[i] = executorService.submit(new Callable(){...}); } for (int i = 0; i < futures.length; ++i) { futures[i].get(); // wait for it to complete } } )); synchronized (mTaskMap) { mTaskMap.put(task.getId(), future); } } public void stopTaskAysnc(int taskId) { executorService.execute(new Runnable(){ Future future = mTaskMap.get(taskId); future.cancel(true); }); } 

我注意到一个奇怪的行为,在我为所有5个任务调用stopTaskAsync()之后,总会有至少一个被停止的任务(即Thread.currentThread.isInterrupted()返回true),其他4个任务继续运行。

我已经通过设置UncaughtExceptionHandler来尝试你的建议,但没有任何结果。

编辑:

此链接解决了该问题: 无法停止使用ExecutorService启动的任务

好吧, Future.cancel(boolean)的javadoc说:

如果任务已经启动,则mayInterruptIfRunning参数确定执行此任务的线程是否应该在尝试停止任务时被中断。

所以很可能确定执行任务的线程中断了。 可能发生的是其中一个

……在这里做很多其他事情..

在不执行所需操作的情况下意外清除了Threadinterrupted状态。 如果你在Thread.interrupt()放置一个断点,你可能会抓住罪犯。

我能想到的另一个选择是任务在捕获中断之前终止,因为它已完成或抛出一些未捕获的exception。 调用Future.get()来确定。 无论如何,正如asdasd所提到的,设置UncaughtExceptionHandler是一个好习惯。

你正在做的是非常危险的:你正在使用一个线程池来执行任务(我称之为下载程序),并使用相同的线程池来执行任务

  • 等待下载程序完成(我称之为控制器)
  • 或要求控制器停止

这意味着如果在控制器启动后达到核心线程数,则下载程序将被放入线程池的队列中,并且控制器线程将永远不会完成。 同样,如果在执行取消任务时达到了核心线程数,则此取消任务将被放入队列中,并且在完成其他任务之前不会执行。

您可能应该使用线程池作为下载程序,另一个用于控制器,以及当前线程来取消控制器。

我想你会在这里找到解决方案。 重点是cancel方法引发InterruptedException。 取消后请检查您的主题是否仍在运行? 你确定你没有尝试中断完成的线程吗? 你确定你的线程没有失败任何其他exception? 尝试设置UncaughtExceptionHandler。