Как правильно перехватывать исключения RuntimeExceptions от Исполнителей?

StackOverflow https://stackoverflow.com/questions/1687977

Вопрос

Скажите, что у меня есть следующий код:

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(myRunnable);

Теперь, если myRunnable бросает RuntimeExcpetion, как я могу это поймать?Одним из способов было бы снабдить меня своим собственным ThreadFactory внедрение для newSingleThreadExecutor() и установите пользовательский uncaughtExceptionHandlers для Threadто, что из этого получается.Другим способом было бы обернуть myRunnable местному жителю (анонимному) Runnable который содержит блок try-catch -block.Возможно, существуют и другие подобные обходные пути.Но...почему-то это кажется грязным, я чувствую, что это не должно быть так сложно.Есть ли чистое решение?

Это было полезно?

Решение

Чистый обходной путь заключается в использовании ExecutorService.submit() вместо того , чтобы execute().Это возвращает вам Future который вы можете использовать для извлечения результата или исключения из задачи:

ExecutorService executor = Executors.newSingleThreadExecutor();
Runnable task = new Runnable() {
  public void run() {
    throw new RuntimeException("foo");
  }
};

Future<?> future = executor.submit(task);
try {
  future.get();
} catch (ExecutionException e) {
  Exception rootException = e.getCause();
}

Другие советы

Украсьте runnable в другом runnable, который улавливает исключения во время выполнения и обрабатывает их:

public class REHandler implements Runnable {
    Runnable delegate;
    public REHandler (Runnable delegate) {
        this.delegate = delegate;
    }
    public void run () {
        try {
            delegate.run ();
        } catch (RuntimeException e) {
            ... your fancy error handling here ...
        }
    }
}

executor.execute(new REHandler (myRunnable));

Почему бы не позвонить ExecutorService#submit(), получить Future вернуться, а затем самостоятельно обрабатывать возможные исключения при вызове Future#get() ?

скаффман прав в том , что использует submit это самый чистый подход.Альтернативный подход заключается в создании подкласса ThreadPoolExecutor и переопределить afterExecute(Runnable, Throwable).Если вы будете следовать этому подходу обязательно позвоните execute(Runnable) вместо того , чтобы submit(Runnable) или afterExecute не будет вызван.

Согласно описанию API:

Метод, вызываемый по завершении выполнения данного Runnable.Этот метод вызывается потоком, который выполнил задачу.Если значение не равно нулю, то Выбрасываемый является неперехваченным RuntimeException или Error это привело к внезапному завершению выполнения.

Примечание:Когда действия заключены в задачи (такие как FutureTask) либо явно или с помощью таких методов, как submit, эти объекты задачи перехватывают и поддерживают вычислительные исключения, и таким образом, они не вызывают внезапного завершения и внутренних исключений являются не передано этому метод.

задача(Callable или Runnable) представлен в ThreadPoolExecutors будет преобразован в FuturnTask, содержит реквизит с именем callable равно заданию, которое вы отправляете.FuturnTask имеет свои собственные run способ следующий.Все исключения или выбрасываемые, добавленные в c.call() будет пойман и помещен в реквизит под названием outcome.При вызове FuturnTask get способ, outcome будет выброшен

FuturnTask.запуск Из исходного кода Jdk1.8

public void run() {
        ...
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    // save ex into `outcome` prop
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        }
        ...
    }

если вы хотите перехватить исключение :

      1.ответ скаффмана
      2.перезапишите `afterExecute` при создании нового ThreadPoolExecutor
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            Throwable cause = null;
            if (t == null && r instanceof Future) {
                try {
                    ((Future<?>) r).get();
                } catch (InterruptedException | ExecutionException e) {
                    cause = e;
                }
            } else if (t != null) {
                cause = t;
            }
            if (cause != null) {
                // log error
            }
        }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top