Какие ограничения у Runnable по обработке исключений?
Что проверяют
Знаете ли вы, куда девается исключение из фоновой задачи. Сигнатуру void run() помнят все, а вот где ошибка пропадает без следа, понимают немногие. Следом почти всегда спрашивают про разницу между execute и submit и про Callable.
Как отвечать
Ограничения следуют из сигнатуры public abstract void run():
- нет
throws: проверяемое исключение вродеIOExceptionнаружу не выпустить. Его ловят внутриrun()и обрабатывают или заворачивают в непроверяемое (UncheckedIOException,RuntimeException); - нет возвращаемого значения: вызывающий код не узнаёт ни результат, ни ошибку, если не завести для этого отдельный канал;
- непроверяемое исключение завершает поток: в голом
Threadоно уходит вThread.UncaughtExceptionHandler. По умолчанию это печать стека вSystem.err, остальные потоки работают дальше. Обработчик ставят черезsetUncaughtExceptionHandlerна поток илиThread.setDefaultUncaughtExceptionHandlerна всё приложение.
Дальше покажите, как это выглядит в пулах:
execute(Runnable): исключение доходит до обработчика потока,ThreadPoolExecutorзаменяет упавший рабочий поток новым;submit(Runnable): задачу оборачиваетFutureTask, исключение сохраняется внутриFutureи всплывает только при вызовеget()в видеExecutionException. Нет вызоваget(), нет и ошибки в логах;scheduleAtFixedRate: одно исключение, и все следующие запуски тихо отменяются.
Если результат или ошибка нужны снаружи, берут Callable<V> с V call() throws Exception или CompletableFuture.runAsync с exceptionally, handle или whenComplete. Для общего логирования переопределяют ThreadPoolExecutor.afterExecute.
Где спотыкаются
Говорят, что необработанное исключение в run() роняет всё приложение. Умирает только этот поток, JVM работает, пока живы другие недемонические потоки.
Отправляют задачи через submit и никогда не вызывают get(). Ошибки не видны нигде, задача просто молча не отработала.
Ставят UncaughtExceptionHandler на потоки пула и удивляются, что он молчит для submit: FutureTask ловит исключение раньше, и в afterExecute параметр Throwable тоже приходит null.