为什么 ScheduledExecutorService 在抛出异常后不再运行任务?

2024-01-12

为了执行定期任务,我查看了Timer http://download.oracle.com/javase/6/docs/api/java/util/Timer.html and ScheduledThreadPoolExecutor http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html(使用单线程)并决定使用后者,因为在reference for Executors.newSingleThreadScheduledExecutor() http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html#newSingleThreadScheduledExecutor%28%29, 它说:

但请注意,如果该单个线程由于关闭之前执行期间的失败而终止,则如果需要执行后续任务,则一个新线程将取代它。

我的计划是使用它来防止我想要监视其他操作的看门狗代码中出现未捕获的异常。我想确定一下并编写了下面的测试,但很快就失败了。看来我做出了错误的假设,或者我的测试有问题?

这是代码:

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

一旦重复任务抛出未捕获的异常,它就被认为已经死亡或处于错误状态。这是一个有点陷阱,除非您检查 Future 来获取错误/异常,否则它也会默默地失败。

如果您不想终止重复任务,则必须捕获异常。


正如 Matt b 在上面的评论中指出的那样,

对于这样的框架代码来说,假设它可以安全地重新启动失败的作业是有问题的 - 它因异常而失败的事实意味着数据可能处于任何类型的状态,并且重新启动作业可能是不安全的工作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 ScheduledExecutorService 在抛出异常后不再运行任务? 的相关文章

随机推荐