Обнаружив, что FutureTask
работает в Executors.newCachedThreadPool ()
на Java 1.6 (и из Eclipse) проглатывает исключения в методе Runnable.run ()
, я попытался найти способ их перехватить, не добавляя throw / catch для всех моих Runnable
реализации.
API предлагает, чтобы переопределение FutureTask.setException ()
должно помочь в этом:
Заставляет это будущее сообщать об исключении ExecutionException с заданным значением throwable в качестве причины, если это Future уже не было установлен или был отменен. Этот метод вызывается изнутри методом run при сбое вычисления.
Однако этот метод не Кажется, он вызывается (работа с отладчиком показывает, что исключение перехвачено FutureTask
, но setException
не вызывается). Я написал следующую программу для воспроизведения моей проблемы:
public class RunTest {
public static void main(String[] args) {
MyFutureTask t = new MyFutureTask(new Runnable() {
@Override
public void run() {
throw new RuntimeException("Unchecked exception");
}
});
ExecutorService service = Executors.newCachedThreadPool();
service.submit(t);
}
}
public class MyFutureTask extends FutureTask<Object> {
public MyFutureTask(Runnable r) {
super(r, null);
}
@Override
protected void setException(Throwable t) {
super.setException(t);
System.out.println("Exception: " + t);
}
}
Мой главный вопрос: как я могу поймать исключения, выброшенные в FutureTask? Почему не вызывается setException
?
Также хотелось бы узнать, почему механизм Thread.UncaughtExceptionHandler
не используется FutureTask
, есть есть причина для этого?
setException
, вероятно, не предназначен для переопределения, но предоставляется для того, чтобы вы могли установить исключение в результате, если возникнет такая необходимость. Что вы хотите сделать, так это переопределить метод done ()
и попытаться получить результат:
public class MyFutureTask extends FutureTask<Object> {
public MyFutureTask(Runnable r) {
super(r, null);
}
@Override
protected void done() {
try {
if (!isCancelled()) get();
} catch (ExecutionException e) {
// Exception occurred, deal with it
System.out.println("Exception: " + e.getCause());
} catch (InterruptedException e) {
// Shouldn't happen, we're invoked when computation is finished
throw new AssertionError(e);
}
}
}
Вы пробовали использовать UncaughtExceptionHandler
?
UncaughtExceptionHandler
. UncaughtExceptionHandler
для потоков пула, укажите ThreadFactory
в вызове Executor.newCachedThreadPool (ThreadFactory)
. setUncaughtExceptionHandler (Thread.UncaughtExceptionHandler eh)
Отправьте задачи с помощью ExecutorService.execute
, потому что только исключения выбрасываются из задач, отправленных с помощью execute
попадает в обработчик неперехваченных исключений. Для Задач, отправленных с помощью ExecutorService.submit
, любое выброшенное исключение считается частью возвращаемого значения задачи. Если задача, отправленная с помощью submit, завершается с исключением, она повторно запускается при вызове Future.get
, заключенного в исключение ExecutionException
Я просмотрел исходный код FutureTask
и не смог найти, где вызывается setException
.
Существует метод innerSetException
из FutureTask.Sync
(внутренний класс FutureTask
), который вызывается в случае выбрасывания Throwable
. методом пробега. Этот метод также вызывается в setException
.
Так что похоже, что javadoc неверен (или его очень сложно понять...).