Я пробовал много разных способов немедленно остановить задачу, запущенную с помощью 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. и я не могу узнать, что задача была остановлена внутри метода call().
Я думаю установить флаг типа cancelled=true после вызова future.cancel(true) и постоянной проверки этого флага в методе call(), я думаю, что это хак, и код может быть очень некрасиво, потому что пользователь может запускать много задач одновременно.
Есть ли более элегантный способ добиться того, чего я хочу?
ИЗМЕНИТЬ:
Это действительно сводит меня с ума. Я потратил почти день на эту проблему сейчас. Я попытаюсь объяснить немного больше проблемы, с которой я столкнулся.
Я делаю следующее, чтобы запустить 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() я просто инициирую сокетное соединение с удаленным сервером, чтобы получить размер файла (и это, безусловно, займет некоторое время), после успешного получения размера файла я запущу 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);
});
}
Я заметил странное поведение: после того, как я вызвал stopTaskAsync() для всех 5 задач, всегда будет по крайней мере одна задача, которая будет остановлена (т.е. Thread.currentThread.isInterrupted() вернет true), и остальные 4 задачи продолжали работать.
И я попробовал ваши предложения, установив UncaughtExceptionHandler, но из этого ничего не выходит.
ИЗМЕНИТЬ:
Проблема была решена по этой ссылке: Не удается остановить задачу который запускается с помощью ExecutorService