Как перехватывать исключения в FutureTask

Обнаружив, что 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 , есть есть причина для этого?

21
задан Shashi 26 July 2013 в 08:18
поделиться

3 ответа

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);
        }
    }
}
20
ответ дан 29 November 2019 в 20:28
поделиться

Вы пробовали использовать UncaughtExceptionHandler ?

  • Вам необходимо реализовать интерфейс UncaughtExceptionHandler .
  • Чтобы установить UncaughtExceptionHandler для потоков пула, укажите ThreadFactory в вызове Executor.newCachedThreadPool (ThreadFactory) .
  • Вы можете установить UncaughtExceptionHandler для созданного потока с помощью setUncaughtExceptionHandler (Thread.UncaughtExceptionHandler eh)

Отправьте задачи с помощью ExecutorService.execute , потому что только исключения выбрасываются из задач, отправленных с помощью execute попадает в обработчик неперехваченных исключений. Для Задач, отправленных с помощью ExecutorService.submit , любое выброшенное исключение считается частью возвращаемого значения задачи. Если задача, отправленная с помощью submit, завершается с исключением, она повторно запускается при вызове Future.get , заключенного в исключение ExecutionException

12
ответ дан 29 November 2019 в 20:28
поделиться

Я просмотрел исходный код FutureTask и не смог найти, где вызывается setException.
Существует метод innerSetException из FutureTask.Sync (внутренний класс FutureTask), который вызывается в случае выбрасывания Throwable. методом пробега. Этот метод также вызывается в setException.
Так что похоже, что javadoc неверен (или его очень сложно понять...).

2
ответ дан 29 November 2019 в 20:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: