Почему ScheduledExecutorService не запускает задачу снова после возникновения исключения? - PullRequest
24 голосов
/ 27 июня 2011

Для выполнения периодических задач я посмотрел на Timer и ScheduledThreadPoolExecutor (с одним потоком) и решил использовать последний, потому что в 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 ]

26 голосов
/ 27 июня 2011

Как только повторяющееся задание сгенерировало неперехваченное исключение, предполагается, что оно умерло или находится в состоянии ошибки. Это что-то вроде ошибки, которая также молча терпит неудачу, если вы не изучите будущее, чтобы получить ошибку / исключение.

Вам нужно перехватывать исключения, если вы не хотите убивать повторяющуюся задачу.


Как указано в комментарии выше в примечании b,

было бы проблематично для кода инфраструктуры, подобного этому, предположить, что он может безопасно перезапустить сбойное задание - тот факт, что он выпал с исключением, означает, что данные могли быть оставлены в любом состоянии, и потенциально это было бы небезопасно. перезапустить работу.

9 голосов
/ 05 октября 2012

matt b указал причину.

было бы проблематично для кода инфраструктуры, подобного этому, предположить, что он может безопасно перезапустить невыполненное задание - тот факт, что оно завершилось с ошибкойисключение означает, что данные могли остаться в любом состоянии, и потенциально было бы небезопасно перезапускать задание.

Следует отметить, что в документации написано ScheduledExecutorService

Если при выполнении какого-либо задания возникает исключение, последующие выполнения подавляются.

И, как говорит Майкл Круссе , смысл создания нового потока состоит в том, чтобы позволить другим задачам продолжить работу.

...