我已经尝试了许多不同的方法来立即停止使用ExecutorService启动的任务,但没有运气。
Future<Void> future = executorService.submit(new Callable<Void>(
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 < / strong>我无法知道任务是从call()方法中停止的。
我正在考虑在调用future.cancel(true)并在call()方法中不断检查该标志后设置一个像 canceled = 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<Void> future = executorService.submit(new Callable<Void>(
public Void call () {
// this is a synchronous call
int fileSize = getFileSize();
System.out.println(Thread.currentThread.isInterrupted());
....
Future<Void> futures = new Future<Void>[5];
for (int i = 0; i < futures.length; ++i) {
futures[i] = executorService.submit(new Callable<Void>(){...});
}
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<Void> future = mTaskMap.get(taskId);
future.cancel(true);
});
}
我注意到一个奇怪的行为,在我为所有5个任务调用stopTaskAsync()之后,总会有至少一个任务得到停止(即Thread.currentThread.isInterrupted()返回true) ,其他4项任务一直在运行。
我已经通过设置UncaughtExceptionHandler来尝试你的建议,但没有任何结果。
修改
此问题已在此链接中解决:Can't stop a task which is started using ExecutorService
答案 0 :(得分:4)
Future.cancel(boolean)
的{{3}}说:
如果任务已经启动,那么mayInterruptIfRunning 参数确定执行此任务的线程是否应该是 因试图停止任务而中断。
所以很可能确定执行任务的线程被中断了。可能发生的是其中一个
......在这里做很多其他的事情......
意外清除Thread
的{{1}}状态而未执行所需操作
处理。如果您在interrupted
中设置断点,则可能会遇到犯罪分子。
我能想到的另一个选择是任务在捕获中断之前终止,因为它已完成或抛出一些未捕获的异常。致电Thread.interrupt()
确定。无论如何,正如asdasd所提到的,设置Future.get()
是一个好习惯。
答案 1 :(得分:2)
你正在做的是非常危险的:你正在使用一个线程池来执行任务(我称之为下载程序),以及相同的线程池来执行任务
这意味着如果在控制器启动后达到核心线程数,则下载程序将被放入线程池的队列中,并且控制器线程将永远不会完成。同样,如果在执行取消任务时达到了核心线程数,则此取消任务将被放入队列中,并且在完成其他任务之前不会执行。
你应该使用一个线程池作为下载程序,另一个用于控制器,以及当前线程来取消控制器。
答案 2 :(得分:0)
我想你会找到解决方案here。重点是cancel方法引发InterruptedException。取消后请检查您的主题是否仍在运行?你确定你没有尝试中断完成的线程吗?你确定你的线程没有失败任何其他异常?尝试设置UncaughtExceptionHandler。