Я использую ScheduledExecutorService для периодического выполнения метода.
p-code:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> handle =
scheduler.scheduleWithFixedDelay(new Runnable() {
public void run() {
//Do business logic, may Exception occurs
}
}, 1, 10, TimeUnit.SECONDS);
Мой вопрос:
Как продолжить работу планировщика, если run ()
вызывает исключение?
Должен ли я попытаться перехватить все исключения в методе run ()
? Или любой встроенный метод обратного вызова для обработки исключения? Спасибо!
Старый вопрос, но принятый ответ не дает объяснения и обеспечивает плохой пример, и большая часть ответа upvoted является правильной на некоторых точках, но наконец поощряет Вас добавлять catch
исключения в каждом Runnable.run()
метод.
я не соглашаюсь потому что:
я думаю, что распространение исключения должно быть выполнено ExecutorService
платформа, и на самом деле это предлагает ту функцию.
Кроме того, попытка быть слишком умным путем попытки к замыканию накоротко ExecutorService
способом работать не является хорошая идея также: платформа может развиться, и Вы хотите использовать ее стандартным способом.
Наконец, позволяя ExecutorService
платформа для создания ее задания не означает обязательно останавливать последующую задачу вызовов.
, Если запланированная задача встречается с проблемой, которая является обязанностью вызывающей стороны перенести или не задача согласно причине проблемы.
Каждый слой имеет его свои обязанности. Хранение их делает код и четким и удобным в сопровождении.
ScheduledExecutorService.scheduleWithFixedDelay()/scheduleAtFixRate()
в их спецификации:
, Если какое-либо выполнение задачи встречается с исключением, последующее выполнение подавлено. Иначе задача только завершится через отмену или завершение исполнителя.
Это означает, что ScheduledFuture.get()
не возвращается при каждом запланированном вызове, но что это возвращается для последнего вызова задачи, которая является отменой задачи: вызванный [1 112] или исключение, добавленное задача.
Настолько обрабатывающий эти ScheduledFuture
возврат для получения исключения с [1 114] выглядит правильным:
try {
future.get();
} catch (InterruptedException e) {
// ... to handle
} catch (ExecutionException e) {
// ... and unwrap the exception OR the error that caused the issue
Throwable cause = e.getCause();
}
<час> , Это выполняет задачу, что для третьего выполнения, выданного, исключение и завершает планирование. В некоторых сценариях мы хотим это.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ScheduledExecutorServiceWithException {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
// variable used to thrown an error at the 3rd task invocation
AtomicInteger countBeforeError = new AtomicInteger(3);
// boolean allowing to leave the client to halt the scheduling task or not after a failure
Future<?> futureA = executor
.scheduleWithFixedDelay(new MyRunnable(countBeforeError), 1, 2, TimeUnit.SECONDS);
try {
System.out.println("before get()");
futureA.get(); // will return only if canceled
System.out.println("after get()");
} catch (InterruptedException e) {
// handle that : halt or no
} catch (ExecutionException e) {
System.out.println("exception caught :" + e.getCause());
}
// shutdown the executorservice
executor.shutdown();
}
private static class MyRunnable implements Runnable {
private final AtomicInteger invocationDone;
public MyRunnable(AtomicInteger invocationDone) {
this.invocationDone = invocationDone;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ", execution");
if (invocationDone.decrementAndGet() == 0) {
throw new IllegalArgumentException("ohhh an Exception in MyRunnable");
}
}
}
}
Вывод:
before get() pool-1-thread-1, execution pool-1-thread-1, execution pool-1-thread-1, execution exception caught :java.lang.IllegalArgumentException: ohhh an Exception in MyRunnable
, Это выполняет задачу, которая выдает исключение при двух первом выполнении и бросает ошибку в третью. Мы видим, что клиент задач может принять решение остановиться или не планирование: здесь я продолжаю в случаях исключения, и я останавливаюсь в случае ошибки.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ScheduledExecutorServiceWithException {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
// variable used to thrown an error at the 3rd task invocation
AtomicInteger countBeforeError = new AtomicInteger(3);
// boolean allowing to leave the client to halt the scheduling task or not after a failure
boolean mustHalt = true;
do {
Future<?> futureA = executor
.scheduleWithFixedDelay(new MyRunnable(countBeforeError), 1, 2, TimeUnit.SECONDS);
try {
futureA.get(); // will return only if canceled
} catch (InterruptedException e) {
// handle that : halt or not halt
} catch (ExecutionException e) {
if (e.getCause() instanceof Error) {
System.out.println("I halt in case of Error");
mustHalt = true;
} else {
System.out.println("I reschedule in case of Exception");
mustHalt = false;
}
}
}
while (!mustHalt);
// shutdown the executorservice
executor.shutdown();
}
private static class MyRunnable implements Runnable {
private final AtomicInteger invocationDone;
public MyRunnable(AtomicInteger invocationDone) {
this.invocationDone = invocationDone;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ", execution");
if (invocationDone.decrementAndGet() == 0) {
throw new Error("ohhh an Error in MyRunnable");
} else {
throw new IllegalArgumentException("ohhh an Exception in MyRunnable");
}
}
}
}
Вывод:
pool-1-thread-1, execution I reschedule in case of Exception pool-1-thread-1, execution I reschedule in case of Exception pool-1-thread-2, execution I halt in case of Error