java 为什么 ScheduledExecutorService 抛出异常后不再运行任务?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6494557/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does a ScheduledExecutorService not run a task again after an exception is thrown?
提问by Hanno Fietz
For executing periodical tasks, I looked at Timer
and ScheduledThreadPoolExecutor
(with a single thread) and decided to use the latter, because in the reference for Executors.newSingleThreadScheduledExecutor()
, it says:
为了执行定期任务,我查看了Timer
和ScheduledThreadPoolExecutor
(使用单个线程)并决定使用后者,因为在 中reference for Executors.newSingleThreadScheduledExecutor()
,它说:
Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.
但是请注意,如果该单个线程在关闭之前的执行过程中由于失败而终止,则在需要执行后续任务时将替换为一个新线程。
My plan was to use this as a safeguard against uncaught exceptions in a watchdog piece of code that I want to monitor other operations. I wanted to make sure and wrote the test below, which promptly failed. It seems I was making wrong assumptions, or is something wrong about my test?
我的计划是使用它来防止我想监视其他操作的看门狗代码中的未捕获异常。我想确保并编写下面的测试,但很快就失败了。似乎我做出了错误的假设,或者我的测试有什么问题?
Here's the code:
这是代码:
@Test
public void testTimer() {
final AtomicInteger cTries = new AtomicInteger(0);
final AtomicInteger cSuccesses = new AtomicInteger(0);
TimerTask task = new TimerTask() {
@Override
public void run()
{
cTries.incrementAndGet();
if (true) {
throw new RuntimeException();
}
cSuccesses.incrementAndGet();
}
};
/*
Timer t = new Timer();
t.scheduleAtFixedRate(task, 0, 500);
*/
ScheduledExecutorService exe = Executors.newSingleThreadScheduledExecutor();
exe.scheduleAtFixedRate(task, 0, 500, TimeUnit.MILLISECONDS);
synchronized (this) {
try {
wait(3000);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
exe.shutdown();
/*
t.purge();
*/
Assert.assertEquals(cSuccesses.get(), 0);
Assert.assertTrue(cTries.get() > 1, String.format("%d is not greater than 1. :(", cTries.get()));
}
回答by Peter Lawrey
Once a repeating task has thrown an uncaught exception it is assumed to have died or be in an error state. It is a bit of a gotcha that it also fails silently unless you examine the Future to get the Error/Exception.
一旦一个重复的任务抛出一个未捕获的异常,它就会被假定已经死亡或处于错误状态。除非您检查 Future 以获取错误/异常,否则它也会默默地失败,这有点麻烦。
You have to catch Exceptions if you don't want to kill the repeating task.
如果您不想终止重复任务,则必须捕获异常。
As matt b points out in the comment above,
正如马特 b 在上面的评论中指出的那样,
it would be problematic for framework code like this to assume it can safely restart a failed job - the fact that it failed with an exception means that the data might have been left in any sort of state, and potentially it would be unsafe to restart the job.
像这样的框架代码假设它可以安全地重新启动失败的作业是有问题的 - 事实上它失败并出现异常意味着数据可能已经处于任何类型的状态,并且重新启动可能是不安全的工作。
回答by user454322
matt bhas given the reason.
matt b给出了原因。
it would be problematic for framework code like this to assume it can safely restart a failed job - the fact that it failed with an exception means that the data might have been left in any sort of state, and potentially it would be unsafe to restart the job.
像这样的框架代码假设它可以安全地重新启动失败的作业是有问题的 - 事实上它失败并出现异常意味着数据可能已经处于任何类型的状态,并且重新启动可能是不安全的工作。
It should be noted that is written in the documentation of ScheduledExecutorService
需要注意的是ScheduledExecutorService的文档中写的
If any execution of the task encounters an exception, subsequent executions are suppressed.
如果任务的任何执行遇到异常,则后续执行将被抑制。
And as Michael Krussesays, the point about creating a new thread is to allow other tasks to continue running.
正如 Michael Krusse所说,创建新线程的目的是让其他任务继续运行。