Отмена будущей задачи в Java
Я хочу отменить задачу, отправленную в ExecutorService, что позволит соответствующему потоку выбрать новую задачу из очереди.
Теперь на этот вопрос много раз отвечали на этом форуме.... как проверка Thread.currentThread().interrupt()
или же catch (InterruptedException e)
, Но если поток управления охватывает несколько методов, то установка этих проверок делает код неуклюжим. Поэтому, если возможно, предложите несколько элегантных способов в Java для достижения этой функциональности.
Проблема, с которой я сталкиваюсь, заключается в том, что future.cancel на самом деле не отменяет задачу. Вместо этого он просто отправляет InterruptedException
к выполнению задачи, и задача состоит в том, чтобы пометить себя завершенной и освободить поток.
Итак, что я сделал, так это то, что мне приходилось помещать приведенный ниже блок кода всякий раз, когда в любом месте выполнения возникало исключение, что явно не выглядит хорошо!
if(e instanceof InterruptedException) {
throw e;
}
Итак, как добиться этой функциональности в следующем фрагменте кода:
public class MonitoringInParallelExp {
public static void main(String[] args) throws InterruptedException {
MyClass1 myClass1 = new MyClass1();
ExecutorService service = Executors.newFixedThreadPool(1);
Future<String> future1 = service.submit(myClass1);
Thread.sleep(2000);
System.out.println("calling cancel in Main");
future1.cancel(true);
System.out.println("finally called cancel in Main");
service.shutdown();
}
}
class MyClass1 implements Callable<String> {
@Override
public String call() throws Exception {
try{
MyClass2 myClass2 = new MyClass2();
myClass2.method2();
} catch (Exception e){
if(e instanceof InterruptedException) {
System.out.println("call:"+"e instanceof InterruptedException="+"true");
throw e;
}
System.out.println("Got exception in method1. " + e);
}
System.out.println("returning Myclass1.method1.exit");
return "Myclass1.method1.exit";
}
}
class MyClass2 {
public void method2() throws Exception{
try{
MyClass3 myClass3 = new MyClass3();
myClass3.method3();
} catch (Exception e){
if(e instanceof InterruptedException) {
System.out.println("method2:"+"e instanceof InterruptedException="+"true");
throw e;
}
System.out.println("Got exception in method2. " + e);
// in case the exception isn't InterruptedExceptionm, do some work here
}
}
}
class MyClass3 {
public void method3() throws Exception{
try{
Thread.sleep(10000);
} catch (Exception e){
if(e instanceof InterruptedException) {
System.out.println("method3:"+"e instanceof InterruptedException="+"true");
throw e;
}
System.out.println("Got exception in method3. " + e);
throw new MyException();
}
}
}
class MyException extends Exception {
}
1 ответ
Неважно, если вы прервете Callable
или нет, потому что в этот момент уже слишком поздно
try{
MyClass2 myClass2 = new MyClass2();
myClass2.method2();
} catch (Exception e){
Ваш звонок в future1.cancel(true);
после Thread.sleep(2000)
на самом деле не отменяет текущую задачу (в этом случае ваш method2
вызов) это только означает, что он должен был быть отменен до его начала.
Документы указывают на это https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html
Попытки отменить выполнение этого задания. Эта попытка потерпит неудачу, если задача уже завершена, уже отменена или не может быть отменена по какой-либо другой причине. Если успешно, и эта задача не была запущена при вызове отмены, эта задача никогда не должна выполняться. Если задача уже запущена, параметр mayInterruptIfRunning определяет, следует ли прерывать поток, выполняющий эту задачу, в попытке остановить задачу.
Если вы хотите отменить текущую задачу, вы хотите использовать volatile boolean
флаг или что-то похожее.