2

我有一个,它通过(可以改为使用)定期ScheduledExecutorService调用RunnablescheduleWithFixedDelay()scheduleAtFixedRate()

现在正在考虑如果发生错误该怎么办。如果它无法从 (*) 中轻松恢复,我希望选择停止所有进一步的调用,但不确定执行此操作的最佳方法。

显然,无法从 Runnable 抛出已检查的异常,因此希望获得有关如何从以下选项中进行选择的任何指导:

scheduledFuture.cancel(false);
...or...
scheduledFuture.cancel(true);
...or...
scheduledExecutorService.shutdown();
...or...
scheduledExecutorService.shutdownNow();
...or...
Throw a custom RuntimeException myself?
...or...
Something else?

(*) 想知道一般情况,但如果有人感兴趣,我目前正在查看的检查异常是ParserConfigurationExceptionDocumentBuilderFactory.newDocumentBuilder(). 如果抛出此错误,则表明存在严重问题,因此我基本上希望调度完全停止,而不是每次都可能重复错误。

4

2 回答 2

1

您也许可以将CallableFuture一起使用。这将允许您从异步任务中抛出已检查的异常,但仍可以根据每个任务的需要进行捕获和处理。

如果您使用这种方法,那么让任务本身决定如何处理异常可能是最有意义的。看到这个答案:

但是,如果您想在任务本身之外处理异常,那么我认为每个任务都需要另一个线程。这是一种可能的选择:

    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);

}
于 2012-12-21T17:01:58.890 回答
1

基于上面的一些有用的评论,这里是我当前代码的要点 - 一些 q 仍然存在,所以欢迎任何进一步的评论:

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();
    }
}
于 2012-12-24T10:54:24.680 回答