tl; dr
Любое исключение, выходящее из вашего метода run
, останавливает всю дальнейшую работу без уведомления.
Всегда используйте try-catch
в вашем методе run
.Попытайтесь восстановить, если вы хотите, чтобы запланированные действия продолжались.
@Override
public void run ()
{
try {
doChore();
} catch ( Exception e ) {
logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + t.getStackTrace() );
}
}
Проблема
Этот вопрос относится к критической уловке с ScheduledExecutorService
: Любое выброшенное исключение или ошибка, достигающая исполнителя, приводит к его остановке. Больше никаких вызовов в Runnable, больше не выполняется работа.Эта остановка работы происходит тихо, вы не будете проинформированы.Это непослушное сообщение в блоге занимательно рассказывает о сложном способе узнать об этом поведении.
Решение
Ответ от yegor256 и ответ от arun_suresh оба кажутся в основном правильными.Две проблемы с этими ответами:
- Ошибки перехвата, а также исключения
- Немного сложно
Ошибки и Исключения?
В Java мы обычно ловим только исключений , а не ошибок .Но в этом особом случае ScheduledExecutorService отказ от перехвата будет означать остановку работы.Таким образом, вы можете поймать оба.Я не уверен на 100% в этом, не зная полностью последствий всех ошибок.Пожалуйста, исправьте меня, если необходимо.
Один из способов отловить как исключения, так и ошибки - перехватить их суперкласс, Throwable .
} catch ( Throwable t ) {
… вместо…
} catch ( Exception e ) {
Простейший подход: просто добавьте Try-Catch
Но оба ответа немного сложны.Просто для справки, я покажу самое простое решение:
Всегда оборачивайте код вашего Runnable в Try-Catch, чтобы отловить все исключения и .
Лямбда-синтаксис
С лямбдой (в Java 8 и более поздних версиях).
final Runnable someChoreRunnable = () -> {
try {
doChore();
} catch ( Throwable t ) { // Catch Throwable rather than Exception (a subclass).
logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + t.getStackTrace() );
}
};
Старомодный синтаксис
Старый-по-старому, до лямбды.
final Runnable someChoreRunnable = new Runnable()
{
@Override
public void run ()
{
try {
doChore();
} catch ( Throwable t ) { // Catch Throwable rather than Exception (a subclass).
logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + t.getStackTrace() );
}
}
};
В каждом Runnable / Callable
Независимо от ScheduledExecutorService
, мне кажется разумным всегда использовать общий try-catch( Exception† e )
in any run
метод Runnable
.То же самое для любого call
метода Callable
.
Полный пример кода
В реальной работе я бы, вероятно,определить Runnable
отдельно, а не вложенно.Но это делает для аккуратного примера все-в-одном.
package com.basilbourque.example;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Demo `ScheduledExecutorService`
*/
public class App {
public static void main ( String[] args ) {
App app = new App();
app.doIt();
}
private void doIt () {
// Demonstrate a working scheduled executor service.
// Run, and watch the console for 20 seconds.
System.out.println( "BASIL - Start." );
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture < ? > handle =
scheduler.scheduleWithFixedDelay( new Runnable() {
public void run () {
try {
// doChore ; // Do business logic.
System.out.println( "Now: " + ZonedDateTime.now( ZoneId.systemDefault() ) ); // Report current moment.
} catch ( Exception e ) {
// … handle exception/error. Trap any unexpected exception here rather to stop it reaching and shutting-down the scheduled executor service.
// logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + e.getStackTrace() );
} // End of try-catch.
} // End of `run` method.
} , 0 , 2 , TimeUnit.SECONDS );
// Wait a long moment, for background thread to do some work.
try {
Thread.sleep( TimeUnit.SECONDS.toMillis( 20 ) );
} catch ( InterruptedException e ) {
e.printStackTrace();
}
// Time is up. Kill the executor service and its thread pool.
scheduler.shutdown();
System.out.println( "BASIL - Done." );
}
}
При запуске.
BASIL - Start.
Сейчас: 2018-04-10T16: 46: 01.423286-07: 00 [America / Los_Angeles]
Сейчас: 2018-04-10T16: 46: 03.449178-07: 00 [America / Los_Angeles]
Сейчас: 2018-04-10T16: 46: 05.450107-07: 00 [Америка / Los_Angeles]
Сейчас: 2018-04-10T16: 46: 07.450586-07: 00 [America / Los_Angeles]
Сейчас: 2018-04-10T16: 46: 09.456076-07: 00 [America / Los_Angeles]
Сейчас: 2018-04-10T16: 46: 11.456872-07: 00 [America / Los_Angeles]
Сейчас: 2018-04-10T16: 46: 13.461944-07: 00 [America / Los_Angeles]
Сейчас: 2018-04-10T16: 46: 15.463837-07: 00 [America / Los_Angeles]
Сейчас: 2018-04-10T16: 46: 17.469218-07: 00 [America / Los_Angeles]
Сейчас: 2018-04-10T16: 46: 19.473935-07: 00 [America / Los_Angeles]
BASIL - Готово.
† Или, возможно, Throwable
вместо Exception
, чтобы поймать Error
объекты тоже.