2010-10-06 2 views
38

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

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

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

В качестве побочного вопроса. Есть ли способ написать общий блок catch 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(); 
     } 
    } 
} 
+3

Отличный вопрос. Интересно, почему в этом только мало кто сталкивается. – whiskeysierra

+0

См. Также http://stackoverflow.com/questions/1687977/how-to-properly-catch-runtimeexceptions-from-executors – Raedwald

ответ

22

Я написал небольшую post об этой проблеме некоторое время назад. У вас есть два варианта:

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

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

+0

Хорошо, я подтвердил это и удалил свой ответ. Благодаря! Не стесняйтесь изменять свой шаг 2, чтобы вдаваться в подробности. –

+2

На самом деле я попробовал # 2 и не смог заставить его работать. Исключение было поймано значительно выше моего блока try/catch в делегировании Runnable, поэтому это, похоже, уступает той же проблеме, что и UncaughtExceptionHandler. –

+0

Я только что принял это. Но Марк говорит, что украшать поставленные задачи с помощью try/catch не ... Я собираюсь попробовать это. – Ivan

12

Предупреждение: Этот метод не применим к запланированными пула потоков исполнителей. Этот ответ был восстановлен за его соответствие другим исполнителям пула потоков. См. Willi's answer.

Override 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; 
    } 
} 
+4

'UncaughExceptionHandler' не работает с запланированными runnables. – whiskeysierra

+0

@Willi: Позвольте мне проверить, а затем я удалю его, если подтвержу. –

+1

Undeleting, поскольку он по-прежнему кажется полезным для нерегулярных исполнителей пула потоков. –

0

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

+1

'ScheduledThreadPoolExecutor' находится в' java.util.concurrent' ... – whiskeysierra

5

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

+0

Как это работает для последующих вызовов? например как вы получаете будущее для второго вызова, после того, как первое вернулось успешно? –

+0

@Mark Если одно выполнение не выполнено, выполнение второго (или третьего, ...) не будет выполняться. Скопировано из исходного javadoc: * Если какое-либо выполнение задачи встречает исключение, последующие исполнения подавляются. * – whiskeysierra

+0

@Willi: Тогда, я думаю, я смущен утверждением OP «кажется, что есть Исключения ...», если это только когда-либо запускается один раз. –

2

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

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

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

TaskUtils.decorateTaskWithErrorHandler(task, errorHandler, isRepeatingTask) 

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

2

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

Смежные вопросы