Обработка исключений в ThreadPools
У меня есть ScheduledThreadPoolExecutor, который, кажется, есть Исключения. Я хочу, чтобы служба-исполнитель уведомила меня, если отправленное Runnable вызывает исключение.
Например, мне бы хотелось, чтобы код ниже, по крайней мере, напечатал IndexArrayOutOfBoundsException stackTrace
threadPool.scheduleAtFixedRate(
new Runnable() {
public void run() {
int[] array = new array[0];
array[42] = 5;
}
},
1000,
1500L,
TimeUnit.MILLISECONDS);
Как побочный вопрос. Есть ли способ написать общий блок catch try для ScheduledThreadPoolExecutor?
//////////КОНЕЦ ОРИГИНАЛЬНОГО ВОПРОСА //////////////
Как было предложено, следующий Decorator хорошо работает.
public class CatcherTask implements Runnable{
Runnable runMe;
public CatcherTask(Runnable runMe) {
this.runMe = runMe;
}
public void run() {
try {
runMe.run();
} catch (Exception ex){
ex.printStackTrace();
}
}
}
Ответы
Ответ 1
Я написал небольшую сообщение об этой проблеме некоторое время назад. У вас есть два варианта:
- Используйте решение, предоставленное Колином Гербертом или
- используйте модифицированную версию решения Mark Peters , но вместо назначения
UncaughtExceptionHandler
вы завершаете каждый представленный runnable в исполняемый файл, который выполняется (вызывает run
) реальный runnable внутри блока try-catch.
ИЗМЕНИТЬ
Как отметил Марк, важно обернуть Runnable
, переданный в ScheduledExecutorService
, а не тот, который был передан в ThreadFactory
.
Ответ 2
Предупреждение. Этот метод не применим к запланированным исполнителям пулов потоков. Этот ответ был восстановлен за его соответствие другим исполнителям пула потоков. См. Ответ Вилли.
Переопределите ThreadFactory
, чтобы предоставить Threads UncaughtExceptionHandler:
ThreadPoolExecutor exec = new ThreadPoolExecutor...;
exec.setThreadFactory(new ExceptionCatchingThreadFactory(exec.getThreadFactory()));
//go on to submit tasks...
private static class ExceptionCatchingThreadFactory implements ThreadFactory {
private final ThreadFactory delegate;
private ExceptionCatchingThreadFactory(ThreadFactory delegate) {
this.delegate = delegate;
}
public Thread newThread(final Runnable r) {
Thread t = delegate.newThread(r);
t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
e.printStackTrace(); //replace with your handling logic.
}
});
return t;
}
}
Ответ 3
Вы можете использовать метод get()
из Future
, который вы получаете, вызывая scheduleAtFixedRate()
. Он выкинет ExecutionException
, если во время выполнения потока произошла утечка.
Ответ 4
Вы также можете использовать ThreadPoolTaskScheduler
из Spring Framework, который предоставляет метод для установки обработчика ошибок и выполняет все обертывание для вас. Поведение по умолчанию зависит от типа задачи:
Если предоставленный ErrorHandler
не является нулевым, он будет использоваться. В противном случае повторяющиеся задачи будут иметь ошибки, подавленные по умолчанию, тогда как задачи с одним выстрелом будут иметь ошибки, распространяемые по умолчанию, поскольку эти ошибки можно ожидать через возвращаемый Future
. В обоих случаях ошибки будут регистрироваться.
Если вы хотите использовать только часть обертки, а не TaskScheduler
, вы можете использовать
TaskUtils.decorateTaskWithErrorHandler(task, errorHandler, isRepeatingTask)
который использует TaskScheduler
внутри.
Ответ 5
Вы можете подклассифицировать ScheduledThreadPoolExecutor и переопределить метод afterExecute для обработки исключений и ошибок для любого вида Runnable, который вы отправляете.
Ответ 6
Подумайте о добавлении статического события в класс ScheduledThreadPoolExecutor, который может вызвать любая из ваших задач при вызове исключения. Таким образом, вы можете использовать это событие для захвата и обработки исключений, возникающих в ваших потоках.