Я пытаюсь использовать ThreadPoolExecutor
класс Java для запуска большого количества тяжеловесных задач с фиксированным количеством потоков. У каждой из задач есть много мест, в которых она может потерпеть неудачу из-за исключений.
Я разделил на подклассы ThreadPoolExecutor
и переопределил afterExecute
метод, который должен обеспечивать любые неперехваченные исключения, возникающие при выполнении задачи. Тем не менее, я не могу заставить его работать.
Например:
public class ThreadPoolErrors extends ThreadPoolExecutor {
public ThreadPoolErrors() {
super( 1, // core threads
1, // max threads
1, // timeout
TimeUnit.MINUTES, // timeout units
new LinkedBlockingQueue<Runnable>() // work queue
);
}
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if(t != null) {
System.out.println("Got an error: " + t);
} else {
System.out.println("Everything's fine--situation normal!");
}
}
public static void main( String [] args) {
ThreadPoolErrors threadPool = new ThreadPoolErrors();
threadPool.submit(
new Runnable() {
public void run() {
throw new RuntimeException("Ouch! Got an error.");
}
}
);
threadPool.shutdown();
}
}
Вывод этой программы: «Все хорошо - ситуация нормальная!» даже если единственный Runnable, представленный в пул потоков, генерирует исключение. Любой ключ к тому, что здесь происходит?
Спасибо!
Ответы:
Из документов :
Когда вы отправите Runnable, он будет помещен в будущее.
Ваш afterExecute должен быть примерно таким:
источник
future.isDone()
? ПосколькуafterExecute
выполняется послеRunnable
завершения, я предполагаю, чтоfuture.isDone()
всегда возвращаетсяtrue
.ВНИМАНИЕ : Следует отметить, что это решение заблокирует вызывающий поток.
Если вы хотите обрабатывать исключения, сгенерированные задачей, то лучше использовать
Callable
, чемRunnable
.Callable.call()
разрешено выдавать проверенные исключения, и они передаются обратно вызывающему потоку:Если
Callable.call()
выбрасывает исключение, это будет завернуто вExecutionException
и брошеноFuture.get()
.Это, вероятно, будет намного предпочтительнее, чем создание подклассов
ThreadPoolExecutor
. Это также дает вам возможность повторно отправить задачу, если исключение является восстанавливаемым.источник
future.get()
вызвана его перегруженная версия.Объяснение этого поведения прямо в javadoc для afterExecute :
источник
Я обошел его, обернув прилагаемый runnable, представленный исполнителю.
источник
whenComplete()
методCompletableFuture
.Я использую
VerboseRunnable
класс из jcabi-log , который проглатывает все исключения и регистрирует их. Очень удобно, например:источник
Другим решением будет использование ManagedTask и ManagedTaskListener .
Вам нужен Callable или Runnable, который реализует интерфейс ManagedTask .
Метод
getManagedTaskListener
возвращает нужный вам экземпляр.И вы реализуете в ManagedTaskListener по
taskDone
методу:Подробнее о жизненном цикле управляемой задачи и слушателе .
источник
Это работает
Это создаст Исполнителя с одним потоком, который может получить много задач; и будет ждать, пока текущий завершит выполнение, чтобы начать со следующего
В случае ошибки или исключения uncaughtExceptionHandler его поймает
источник
Если вы хотите отслеживать выполнение задачи, вы можете вращать 1 или 2 потока (может быть, больше в зависимости от нагрузки) и использовать их для получения задач из оболочки ExecutionCompletionService.
источник
Если вы
ExecutorService
пришли из внешнего источника (то есть невозможно подклассThreadPoolExecutor
и переопределитьafterExecute()
), вы можете использовать динамический прокси для достижения желаемого поведения:источник
Это происходит из - за
AbstractExecutorService :: submit
оборачивает свойrunnable
INTORunnableFuture
(ничего , кромеFutureTask
) , как показано нижеЗатем
execute
передам егоWorker
иWorker.run()
позвоним ниже.источник
Это похоже на решение МММ, но немного более понятно. Пусть ваши задачи расширяют абстрактный класс, заключающий в себе метод run ().
источник
Вместо того чтобы создавать подклассы ThreadPoolExecutor, я бы предоставил ему экземпляр ThreadFactory, который создает новые потоки и предоставляет им UncaughtExceptionHandler.
источник