Вопрос

После того, как обнаружил это FutureTask Бег в Executors.newCachedThreadPool() на Java 1.6 (и из Eclipse) поглощает исключения в Runnable.run() Метод, я попытался придумать способ поймать их, не добавляя бросок/улов ко всем моим Runnable реализации.

API предполагает, что это переоценивает FutureTask.setException() должен помочь в этом:

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

Однако этот метод, похоже, не называется (бег с отладчиком показывает, что исключение поймано 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) вызов.
  • Вы можете установить UncaughtexceptionHandler для созданного потока через setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

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

Гораздо лучшее решение:Java FutureTask проверка завершения

Когда вы звоните futureTask.get() Чтобы получить результат вычислений, он бросит исключение (выполнение ExecutionException), если в основном Runnable/Callable бросил исключение.

ExecutionException.getCause() вернет исключение, что Runnable/Callable выбросить.

Это также сделает другое исключение, если Runnable/Callable был отменен.

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

Есть три стандартных способа и один импровизированный путь. 1. Используйте UncaughtexceptionHandler, установите UncaughtexceptionHandler для созданного потока как

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable ex) {..}}

*Но ограничение состоит в том, что оно улавливает исключение, брошенное потоком, но в случае будущей задачи оно проглатывается. 2. Используйте afterExecute После создания пользовательского ThreadPoolexeCutor с крюком, который был предоставлен специально для этой цели. Просматривая код ThreadPoolexeCutor, через отправку> выполнить (есть workqueue, workQueue.offer), задачи добавляются в очередь работы

   final void runWorker(Worker arg0) {
  Thread arg1 = Thread.currentThread();
  Runnable arg2 = arg0.firstTask;
  ..
     while(arg2 != null || (arg2 = this.**getTask()**) != null) {
        arg0.lock();
        ..
        try {
           this.beforeExecute(arg1, arg2);
           Object arg4 = null;
           try {
              arg2.run();
           } catch (RuntimeException arg27) {
             ..
           } finally {
              this.**afterExecute**(arg2, (Throwable)arg4);
           }

  }

getTask() {..
 this.workQueue.**poll**();
..}
  1. Затем третий использует Simple Try Catch внутри метода вызова, но вы не можете поймать исключение снаружи здесь.

  2. Обходной путь вызывает все методы вызова из метода вызова задачи, фабрика, которая выпускает Callables.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top