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

时间:2011-06-27 14:36:36

标签: java error-handling threadpool

为了执行定期任务,我查看了TimerScheduledThreadPoolExecutor(使用单个帖子)并决定使用后者,因为在reference for Executors.newSingleThreadScheduledExecutor()中,它说:

  

但请注意,如果此单个线程因关闭前执行期间的故障而终止,则在需要执行后续任务时,新的线程将取代它。

我的计划是使用它作为防范未监视异常的保护措施,以防止我想要监视其他操作的监视程序代码。我想确认并编写下面的测试,这很快就失败了。看来我做错了假设,或者我的测试有些不对劲?

以下是代码:

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

2 个答案:

答案 0 :(得分:26)

一旦重复任务抛出未捕获的异常,就会假定它已经死亡或处于错误状态。除非你检查Future以获得错误/异常,否则它也会无声地失败。

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


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

  

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

答案 1 :(得分:9)

matt b 已经说明了原因。

  

像这样的框架代码可能会有问题   安全地重新启动失败的作业 - 它失败的事实   异常意味着数据可能已被保留在任何类型中   状态,并且可能重新开始工作是不安全的。



应该注意的是,它写在ScheduledExecutorService

的文档中
  

如果任务的任何执行遇到异常,则后续   执行被压制。

正如 Michael Krusse 所说,关于创建新线程的观点是允许其他任务继续运行。