Java «завершает» поток при исключении

#java #multithreading

#java #многопоточность

Вопрос:

Я использую несколько потоков для выполнения некоторой сложной (и подверженной ошибкам) обработки большого набора данных. Я требую, чтобы все потоки завершили выполнение, независимо от того, выдают ли они исключение или завершаются нормально (значение не возвращается), прежде чем программа сможет продолжить. Я использую a CountDownLatch для достижения этой цели и an ExecutorService для фактического выполнения заданий. Я хочу, чтобы рабочие потоки (давайте назовем их JobManager -s для аргументации) уведомляли защелку, даже если они генерируют исключение. Выполнение задания JobManager может занять от секунды до часа и может завершиться неудачей в любой момент. Идея состоит в том, чтобы вызвать метод «финализатора» JobManager , если генерируется исключение. Теперь ExecutorService ему нравится ловить исключения или скрывать истинное происхождение тех, которых у него нет. У меня есть несколько способов обойти это, но ни один из них не является удовлетворительным:

  1. Используйте ExecutorService#execute(Runnable r) вместо submit(Runnable r) . Я могу это сделать, поскольку меня не волнует возвращаемое значение JobManager . Я предоставил пользовательский ThreadFactory интерфейс, который присоединяет UncaughtExceptionHandler к каждому вновь созданному потоку. Проблема с этим подходом заключается в том, что при UncaughtExceptionHandler#uncaughtException(Thread t, Throwable e) вызове t ‘s Runnable имеет тип ThreadPoolExecutor$Worker , а не тип JobManager , что не позволяет мне вызывать метод «финализатора».

  2. Используйте пользовательский ExecutorService и переопределите afterExecute(Runnable r, Throwable t) метод. Это связано с той же проблемой, что и 1.

  3. Оберните все JobManager#doWork() в catch инструкцию и используйте возвращаемое значение, чтобы указать, было ли вызвано исключение. Затем я могу submit использовать задания и FutureTask#get() определять, было ли вызвано исключение. Мне не нравится это решение, потому что я чувствую, что коды возврата — неправильный инструмент, когда у вас есть сложный механизм исключения. Более того, get() будет ждать (если не прервано), что означает, что я не могу немедленно обрабатывать ошибки в других потоках.

  4. Избавьтесь от CountDownLatch . Сохраните все Future s в списке и повторно вводите, пока я не буду удовлетворен состояниями. Это может сработать, но похоже на грязный взлом.

Любые предложения приветствуются.

Комментарии:

1. Я знаю, что это не очень полезно, но… 1 для действительно хорошего форматирования.

2. Идея на самом деле не в том, чтобы «вызвать метод «финализатора» JobManager, если генерируется исключение». Это всего лишь одна из возможных реализаций. Идея состоит в том, чтобы на самом деле не использовать методы завершения. Я настоятельно рекомендую вам переписать свой заголовок, чтобы выразить вашу реальную проблему.

Ответ №1:

Насколько я понимаю, вы можете использовать простой try finally блок:

 public class JobManager {
    public void doWork() {
        try {
            ...
        } finally {
            countDownLatch.countDown();
        }
    }
}