#java #multithreading
#java #многопоточность
Вопрос:
Я использую несколько потоков для выполнения некоторой сложной (и подверженной ошибкам) обработки большого набора данных. Я требую, чтобы все потоки завершили выполнение, независимо от того, выдают ли они исключение или завершаются нормально (значение не возвращается), прежде чем программа сможет продолжить. Я использую a CountDownLatch
для достижения этой цели и an ExecutorService
для фактического выполнения заданий. Я хочу, чтобы рабочие потоки (давайте назовем их JobManager
-s для аргументации) уведомляли защелку, даже если они генерируют исключение. Выполнение задания JobManager
может занять от секунды до часа и может завершиться неудачей в любой момент. Идея состоит в том, чтобы вызвать метод «финализатора» JobManager
, если генерируется исключение. Теперь ExecutorService
ему нравится ловить исключения или скрывать истинное происхождение тех, которых у него нет. У меня есть несколько способов обойти это, но ни один из них не является удовлетворительным:
-
Используйте
ExecutorService#execute(Runnable r)
вместоsubmit(Runnable r)
. Я могу это сделать, поскольку меня не волнует возвращаемое значениеJobManager
. Я предоставил пользовательскийThreadFactory
интерфейс, который присоединяетUncaughtExceptionHandler
к каждому вновь созданному потоку. Проблема с этим подходом заключается в том, что приUncaughtExceptionHandler#uncaughtException(Thread t, Throwable e)
вызовеt
‘sRunnable
имеет типThreadPoolExecutor$Worker
, а не типJobManager
, что не позволяет мне вызывать метод «финализатора». -
Используйте пользовательский
ExecutorService
и переопределитеafterExecute(Runnable r, Throwable t)
метод. Это связано с той же проблемой, что и 1. -
Оберните все
JobManager#doWork()
вcatch
инструкцию и используйте возвращаемое значение, чтобы указать, было ли вызвано исключение. Затем я могуsubmit
использовать задания иFutureTask#get()
определять, было ли вызвано исключение. Мне не нравится это решение, потому что я чувствую, что коды возврата — неправильный инструмент, когда у вас есть сложный механизм исключения. Более того,get()
будет ждать (если не прервано), что означает, что я не могу немедленно обрабатывать ошибки в других потоках. -
Избавьтесь от
CountDownLatch
. Сохраните всеFuture
s в списке и повторно вводите, пока я не буду удовлетворен состояниями. Это может сработать, но похоже на грязный взлом.
Любые предложения приветствуются.
Комментарии:
1. Я знаю, что это не очень полезно, но… 1 для действительно хорошего форматирования.
2. Идея на самом деле не в том, чтобы «вызвать метод «финализатора» JobManager, если генерируется исключение». Это всего лишь одна из возможных реализаций. Идея состоит в том, чтобы на самом деле не использовать методы завершения. Я настоятельно рекомендую вам переписать свой заголовок, чтобы выразить вашу реальную проблему.
Ответ №1:
Насколько я понимаю, вы можете использовать простой try
finally
блок:
public class JobManager {
public void doWork() {
try {
...
} finally {
countDownLatch.countDown();
}
}
}