我有一个ScheduledExecutorService
,会定期通过Runnable调用scheduleWithFixedDelay()
(可能会使用scheduleAtFixedRate()
代替)。
现在正在考虑如果发生错误该怎么办。如果它是不能从(*)中轻易恢复的东西,我想选择停止所有进一步的调用,但不确定最好的方法。
显然不能从Runnable中检查异常,所以我们将非常感谢您如何选择以下内容:
scheduledFuture.cancel(false);
...or...
scheduledFuture.cancel(true);
...or...
scheduledExecutorService.shutdown();
...or...
scheduledExecutorService.shutdownNow();
...or...
Throw a custom RuntimeException myself?
...or...
Something else?
(*)想知道一般情况但是如果有人感兴趣,我正在查看的已检查异常是从DocumentBuilderFactory.newDocumentBuilder()抛出的ParserConfigurationException。如果这被抛出,则表示存在严重问题,因此我基本上喜欢完全停止计划而不是每次都可能重复错误。
答案 0 :(得分:1)
您可以使用Callable和Future。这将允许您从异步任务中抛出已检查的异常,但仍然可以根据需要捕获和处理每个任务。
如果您使用该方法,那么允许任务本身决定如何处理异常可能是最有意义的。看到这个答案:
但是,如果你想在任务本身之外处理异常,那么我认为每个任务都需要另一个线程。这是一个可能的选择:
ScheduledExecutorService scheduleExecutor;
scheduleExecutor = = Executors.newScheduledThreadPool(10); // or whatever
ExecutorService workerExecutor;
workerExecutor = Executors.newSingleThreadExecutor(); // or whatever
public void schedule(final long fixedDelay) {
scheduleExecutor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
Future<Void> future = workerExecutor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
// Do work here. Throw appropiate exception as needed.
return null;
}
});
// Now you can catch and handle the exception in whatever
// way you need to. You can cancel just this task (which is likely
// redundant by this point), or you can choose to shutdown
// all other scheduled tasks (which I doubt is what you want).
try {
future.get();
} catch (Exception e) {
future.cancel(true);
}
}
}, 0, fixedDelay, TimeUnit.MILLISECONDS);
}
答案 1 :(得分:1)
基于上面的一些有用的评论,这是我当前代码的要点 - 还有一些问题仍然存在,欢迎任何进一步的评论:
public class ScheduledTask implements Runnable {
// Configurable values
private static final int CORE_THREAD_POOL_SIZE = 1;
private static final int INITIAL_DELAY_MS = 0;
private static final int INTERVAL_MS = 1000;
private final ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(ScheduledTask.CORE_THREAD_POOL_SIZE);
private ScheduledFuture<?> scheduledFuture;
public void run() {
try {
try {
// Do stuff
} catch RecoverableCheckedException rce { // E.g. SAXException
// Log and handle appropriately
}
} catch UnrecoverableCheckedException uce { // E.g. ParserConfigurationException
// Not 100% happy with this. It means the caller would need to call
// getCause() to get the real Exception in this case. But other
// RuntimeExceptions wouldn't be wrapped. Could consider catching
// and wrapping all RuntimeExceptions but I like that even less!
throw new RuntimeException(uce);
}
}
public boolean isScheduling() {
return (this.scheduledFuture != null)
&& (!this.scheduledFuture.isDone());
}
// May not be needed but provided in case this class is shared.
public boolean isShutdown() {
return scheduledExecutorService.isShutdown();
}
public void start() {
// If the Executor Service has already been shutdown, would expect
// a RejectedExecutionException to be thrown here(?) Not sure what
// would happen if this method were called when isScheduling() is
// true?
this.scheduledFuture =
this.scheduledExecutorService.scheduleWithFixedDelay(
this,
ScheduledTask.INITIAL_DELAY_MS,
ScheduledTask.INTERVAL_MS,
TimeUnit.MILLISECONDS);
}
// To be called once at the very end - e.g. on program termination.
public void shutdown() {
this.scheduledExecutorService.shutdown();
}
}