Как поймать исключения в FuturoTask
-
30-09-2019 - |
Вопрос
После того, как обнаружил это 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**();
..}
Затем третий использует Simple Try Catch внутри метода вызова, но вы не можете поймать исключение снаружи здесь.
Обходной путь вызывает все методы вызова из метода вызова задачи, фабрика, которая выпускает Callables.