我使用ScheduledExecutorService
来安排一些需要定期运行的任务。
我想知道这个代码是否能够在发生异常时恢复计划。
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
this.startMemoryUpdateSchedule(service);//See below method
//Recursive method to handle exception when run schedule task
private void startMemoryUpdateSchedule(ScheduledExecutorService service) {
ScheduledFuture<?> future = service.scheduleWithFixedDelay(new MemoryUpdateThread(), 1, UPDATE_MEMORY_SCHEDULE, TimeUnit.MINUTES);
try {
future.get();
} catch (ExecutionException e) {
e.printStackTrace();
logger.error("Exception thrown for thread",e);
future.cancel(true);
this.startMemoryUpdateSchedule(service);
} catch(Exception e) {
logger.error("Other exception ",e);
}
}
答案 0 :(得分:1)
你可能应该在while(true)
循环中包含try块,因为如果第一次运行没有抛出异常,你将退出你的方法,如果第二次调用抛出一个,你将无法捕获它。 / p>
我还会在自己的线程中运行递归调用,以避免在出现问题时发生StackOverFlow错误的风险。
所以它看起来像这样:
private void startMemoryUpdateSchedule(final ScheduledExecutorService service) {
final ScheduledFuture<?> future = service.scheduleWithFixedDelay(new MemoryUpdateThread(), 1, UPDATE_MEMORY_SCHEDULE, TimeUnit.MINUTES);
Runnable watchdog = new Runnable() {
@Override
public void run() {
while (true) {
try {
future.get();
} catch (ExecutionException e) {
//handle it
startMemoryUpdateSchedule(service);
return;
} catch (InterruptedException e) {
//handle it
return;
}
}
}
};
new Thread(watchdog).start();
}
答案 1 :(得分:1)
尝试使用专为此目的而设计的VerboseRunnable
jcabi-log类:
import com.jcabi.log.VerboseRunnable;
Runnable runnable = new VerboseRunnable(
Runnable() {
public void run() {
// do business logic, may Exception occurs
}
},
true // it means that all exceptions will be swallowed and logged
);
现在,当任何人调用runnable.run()
时,不会抛出任何异常。相反,它们被吞下并记录(到SLF4J)。
答案 2 :(得分:0)
我已经按照讨论的方式添加了循环。
public void startMemoryUpdateSchedule(final ScheduledExecutorService service) {
boolean retry = false;
do {
ScheduledFuture<?> future = null;
try {
retry = false;
future = service.scheduleWithFixedDelay(new MemoryUpdateThread(), 1, UPDATE_MEMORY_SCHEDULE, TimeUnit.SECONDS);
future.get();
} catch (ExecutionException e) {
// handle
future.cancel(true);
retry = true;
} catch(Exception e) {
// handle
}
} while (retry);
}
答案 3 :(得分:0)
ScheduledExecutorService.scheduleWithFixedDelay(Runnable, long, long, TimeUnit)
抛出RejectedExecutionException
(RuntimeException的子节点)==&gt;我们可以抓住它和它再次重试提交。
现在future.get()
应该返回一次执行的结果,我们需要在循环中调用它。
此外,一次执行失败不会影响下一次计划执行,这会将ScheduledExecutorService与执行同一thread =&gt;中的计划任务的TimerTask区分开来。在TimerTask的情况下,一次执行失败将中止调度(http://stackoverflow.com/questions/409932/java-timer-vs-executorservice) 我们只需要捕获Future.get()抛出的所有三个异常,但是我们不能重新抛出它们,那么我们将无法获得后续执行的结果。
代码可以是:
public void startMemoryUpdateSchedule(final ScheduledExecutorService service) {
final ScheduledFuture<?> future;
try {
future = service.scheduleWithFixedDelay(new MemoryUpdateThread(),
1, UPDATE_MEMORY_SCHEDULE, TimeUnit.SECONDS);
} catch (RejectedExecutionException ree) {
startMemoryUpdateSchedule(service);
return;
}
while (true) {
try {
future.get();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
} catch (ExecutionException ee) {
Throwable cause = ee.getCause();
// take action, log etc.
} catch (CancellationException e) {
// safety measure if task was cancelled by some external agent.
}
}
}