Обработка исключений в ThreadPools - PullRequest
41 голосов
/ 06 октября 2010

У меня есть ScheduledThreadPoolExecutor, который, кажется, ест исключения. Я хочу, чтобы моя служба-исполнитель уведомляла меня, если отправленный Runnable вызывает исключение.

Например, я хотел бы, чтобы приведенный ниже код по крайней мере распечатывал stackTrace IndexArrayOutOfBoundsException

threadPool.scheduleAtFixedRate(
  new Runnable() {
    public void run() {
      int[] array = new array[0];
      array[42] = 5;
    }
  },
  1000,
  1500L,
  TimeUnit.MILLISECONDS);

Как побочный вопрос. Есть ли способ написать общий блок try try для ScheduledThreadPoolExecutor?

////////// КОНЕЦ ОРИГИНАЛЬНОГО ВОПРОСА //////////////

Как и предполагалось, следующий Декоратор работает хорошо.

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

Ответы [ 6 ]

24 голосов
/ 06 октября 2010

Я недавно написал небольшой пост об этой проблеме. У вас есть два варианта:

  1. Используйте решение , предоставленное Колином Гербертом или
  2. использует модифицированную версию решения Mark Peters , но вместо назначения UncaughtExceptionHandler вы помещаете каждый представленный исполняемый файл в собственный исполняемый файл, который выполняет (вызывает run) реальный исполняемый файл внутри попытки -catch-блок.

EDIT
Как отметил Марк, важно обернуть Runnable, переданный ScheduledExecutorService, вместо того, чтобы передать ThreadFactory.

13 голосов
/ 06 октября 2010

Предупреждение : Этот метод не применим к запланированным исполнителям пула потоков.Этот ответ был удален из-за его актуальности для других исполнителей пула потоков.См. ответ Вилли .

Переопределите ThreadFactory, чтобы дать Потокам 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;
    }
}
5 голосов
/ 06 октября 2010

Вы можете использовать метод get() из Future, который вы получаете, вызывая scheduleAtFixedRate(). Он выдаст ExecutionException, если во время выполнения потока возникла исключительная ситуация.

3 голосов
/ 07 июня 2013

Вы также можете использовать ThreadPoolTaskScheduler из Spring Framework , который предоставляет метод для установки обработчика ошибок и делает все переносы за вас.Поведение по умолчанию зависит от типа задачи:

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

Если вы хотите использовать только оберточную часть, а не TaskScheduler, вы можете использовать

TaskUtils.decorateTaskWithErrorHandler(task, errorHandler, isRepeatingTask)

, которую TaskScheduler использует внутренне.

2 голосов
/ 26 октября 2015

Вы можете создать подкласс ScheduledThreadPoolExecutor и переопределить метод afterExecute для обработки исключений и ошибок для любого вида Runnable, который вы отправляете.

0 голосов
/ 06 октября 2010

Подумайте о добавлении статического события в ваш ScheduledThreadPoolExecutor класс, который может вызвать любая из ваших задач в случае возникновения исключения. Таким образом, вы можете использовать это событие для захвата и обработки исключений, возникающих в ваших потоках.

...