Как правильно поймать RuntimeExceptions от исполнителей?
сказать, что у меня есть следующий код:
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(myRunnable);
теперь, если myRunnable
бросает!--2-->, Как я могу поймать его? Одним из способов было бы поставить мой собственный ThreadFactory
реализации newSingleThreadExecutor()
и настройки uncaughtExceptionHandler
С Thread
s, которые выходят из него. Другой способ-обернуть myRunnable
для местного (анонимного) Runnable
который содержит блок try-catch. Возможно,есть и другие подобные обходные пути. Но... почему-то это кажется грязным, я чувствую, что это не должно быть так сложно. Есть есть ли чистое решение?
5 ответов
чистый обходной путь должен использовать 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()
?
skaffman правильно, что с помощью submit
самый чистый подход. Альтернативный подход-подкласс ThreadPoolExecutor
и заменить afterExecute(Runnable, Throwable)
. Если вы будете следовать этому подходу обязательно позвоните execute(Runnable)
, а не submit(Runnable)
или afterExecute
не будет вызван.
согласно описанию API:
метод вызывается по завершении исполнение данного Runnable. Этот метод вызывается потоком, который исполнено задача. Если значение не равно null, Throwable-это не пойманный
RuntimeException
илиError
что вызвало казнь резко прекратится.Примечание: когда действия заключены в задачи (например, FutureTask) либо явно или с помощью таких методов, как submit, эти объекты задачи поймать и поддерживать вычислительные исключения и поэтому они не вызывают резкого прекращение, и внутреннее исключение составляют не передано этому метод.
задача(Callable
или Runnable
) представлен ThreadPoolExecutors
будет преобразовано в FuturnTask
, содержит опору с именем callable
равно задаче, которую вы отправляете. FuturnTask имеет свой собственный run
метод следующим образом. Все исключения или throwable throwed in 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. skaffman ответ
- 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
}
}