简体   繁体   English

如何使用 ScheduledExecutorService 处理重复任务中的错误?

[英]How to handle errors in a repeated task using ScheduledExecutorService?

I have a ScheduledExecutorService , which invokes a Runnable periodically via scheduleWithFixedDelay() (could have used scheduleAtFixedRate() instead).我有一个ScheduledExecutorService ,它通过scheduleWithFixedDelay()定期调用Runnable (可以使用scheduleAtFixedRate()代替)。

Am now considering what to do if an error occurs.我现在正在考虑如果发生错误该怎么办。 If it's something that can't easily be recovered from(*) I'd like the option of stopping all further invocations but not sure of the best way of doing this.如果它无法轻易从 (*) 中恢复,我想要停止所有进一步调用的选项,但不确定这样做的最佳方法。

Apparently checked exceptions can't be thrown from a Runnable so would appreciate any guidance on how to choose from the following:显然,无法从 Runnable 抛出已检查的异常,因此希望您能提供有关如何从以下选项中进行选择的任何指导:

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

(*) Would like to know the general case but in case anyone's interested, the checked exception I'm currently looking at is a ParserConfigurationException thrown from DocumentBuilderFactory.newDocumentBuilder() . (*) 想知道一般情况,但如果有人感兴趣,我目前正在查看的已检查异常是从DocumentBuilderFactory.newDocumentBuilder()抛出的ParserConfigurationException If this is thrown, it indicates a serious problem so I'd basically like the scheduling to completely stop rather than potentially repeating the error every time.如果抛出此问题,则表示存在严重问题,因此我基本上希望调度完全停止,而不是每次都可能重复错误。

You can use a Callable along with the Future perhaps.您可以将CallableFuture一起使用。 This will let you throw a checked exception from within an asynchronous task, yet still catch and handle as needed per task.这将允许您从异步任务中抛出已检查的异常,但仍然可以根据每个任务的需要捕获和处理。

If you use that approach, then allowing the task itself to decide how to handle the exception probably makes the most sense.如果您使用这种方法,那么让任务本身决定如何处理异常可能是最有意义的。 See this answer:看到这个答案:

However, if you want to handle the exception outside of the task itself, then I think you will need another thread for each task.但是,如果您想在任务本身之外处理异常,那么我认为每个任务都需要另一个线程。 Here's one possible option:这是一种可能的选择:

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

}

Based on a few of the helpful comments above here's the gist of my current code - a few q's remain within so would welcome any further comments:基于上面的一些有用的评论,这里是我当前代码的要点 - 一些问题仍然存在,所以欢迎任何进一步的评论:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用ScheduledExecutorService重新安排任务? - How to reschedule a task using a ScheduledExecutorService? 使用 ScheduledExecutorService 安排每月任务 - Schedule monthly task using ScheduledExecutorService 在无休止的任务上使用ScheduledExecutorService时如何执行垃圾回收? - How to perform garbage collection when using ScheduledExecutorService on neverending task? 如何使用 ScheduledExecutorService 每天在特定时间运行某些任务? - How to run certain task every day at a particular time using ScheduledExecutorService? 如何从 ScheduledExecutorService 中删除任务? - How to remove a task from ScheduledExecutorService? 使用ScheduledExecutorService在Java中定期运行任务 - Using a ScheduledExecutorService to run a task on a periodic basis in Java 使用ScheduledExecutorService每天安排任务? - Schedule a task every day using ScheduledExecutorService? 如何有效地取消定期的ScheduledExecutorService任务 - How to effectively cancel periodic ScheduledExecutorService task 如何在特定时间停止/取消ScheduledExecutorService中的任务? - How to stop/cancel a task in ScheduledExecutorService at particular time? 如果上一个未完成,如何不启动ScheduledExecutorService任务 - How not to start ScheduledExecutorService task if previous one is not finished
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM