Обработка ошибок и отмена
Корректно передавайте сведения о сбоях
«Обработка ошибок и отмена» — бесплатный урок Java Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Сбои в дереве задач
Когда подзадачи выполняются параллельно, ошибки могут возникнуть в любой ветви. Структурированный параллелизм предоставляет дисциплинированный способ передавать эти ошибки родительской задаче.
В этом уроке рассматриваются исключения, отмена, прерывание и ограничения времени.
Где возникают исключения
Подзадача, выбросившая исключение, не приводит к немедленному аварийному завершению программы. Исключение сохраняется в дескрипторе Subtask. Место его возникновения зависит от политики:
ShutdownOnFailure: вthrowIfFailed()ShutdownOnSuccess: вresult(), если ни одна подзадача не завершилась успешно
Передача ошибки с помощью throwIfFailed
Здесь подзадача завершается с ошибкой. throwIfFailed() повторно выбрасывает её, оборачивая в ExecutionException, которую мы перехватываем в main.
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
scope.fork(() -> "ok");
scope.fork(() -> { throw new RuntimeException("boom"); });
scope.join();
scope.throwIfFailed();
System.out.println("never reached");
} catch (ExecutionException e) {
System.out.println("Caught cause: " + e.getCause().getMessage());
}
}
}Преобразование в пользовательское исключение
throwIfFailed принимает функцию, которая оборачивает причину в выбранный Вами тип исключения, сохраняя чистоту программного интерфейса.
import java.util.concurrent.StructuredTaskScope;
class DataAccessException extends Exception {
DataAccessException(Throwable cause) { super(cause); }
}
public class Main {
public static void main(String[] args) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
scope.fork(() -> { throw new RuntimeException("db down"); });
scope.join();
scope.throwIfFailed(DataAccessException::new);
} catch (DataAccessException e) {
System.out.println("Wrapped: " + e.getCause().getMessage());
}
}
}Автоматическая отмена
Когда одна подзадача завершается с ошибкой в рамках ShutdownOnFailure, scope отменяет соседние подзадачи, прерывая их потоки. Вам не нужно самостоятельно писать код отмены.
Это предотвращает напрасную работу и оставшиеся без управления задачи.
Прерывание — это механизм
Отмена выполняется за счёт прерывания виртуального потока подзадачи. Согласованно работающий код должен:
- Позволять блокирующим вызовам выбрасывать
InterruptedException - Периодически проверять
Thread.currentThread().isInterrupted()в длинных циклах
Реакция на прерывание
Эта задача проверяет флаг прерывания в цикле, чтобы досрочно остановиться при завершении работы scope.
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().start(() -> {
long count = 0;
while (!Thread.currentThread().isInterrupted()) {
count++;
if (count == 1_000_000) break;
}
System.out.println("Stopped after " + count + " iterations");
});
t.join();
}
}Крайние сроки с joinUntil
Чтобы ограничить общее время, используйте joinUntil(Instant). Если крайний срок наступает до завершения всех подзадач, этот вызов выбрасывает TimeoutException, а scope завершает работу остальных подзадач.
Типичный вид с ограничением времени
Типичное разветвление с ограничением времени выглядит так. Крайний срок применяется ко всей группе, а не к каждой подзадаче отдельно.
import java.time.*;
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
scope.fork(() -> "fast");
scope.joinUntil(Instant.now().plus(Duration.ofSeconds(2)));
scope.throwIfFailed();
System.out.println("Completed within deadline");
} catch (TimeoutException e) {
System.out.println("Deadline exceeded");
} catch (ExecutionException e) {
System.out.println("A subtask failed");
}
}
}Всегда повторно проверяйте после join
Правило таково: после join() или joinUntil всегда вызывайте throwIfFailed() или читайте result(), прежде чем доверять значению какой-либо подзадачи. Пропуск этой проверки может скрыть ошибки.
Гарантированное корректное завершение
Как бы ни завершился scope — обычно, из-за ошибки или по истечении времени — закрытие блока try с ресурсами гарантирует завершение каждого потока подзадачи. Утечек и оставшихся без управления задач не будет.
Быстрая проверка
Вспомните, как останавливаются соседние подзадачи.
Итоги
Вы изучили обработку ошибок и отмену:
- Исключения возникают в
throwIfFailed()илиresult() - Причины можно преобразовать в пользовательские исключения через
throwIfFailed(mapper) - Отмена выполняется через прерывание потока; задачи должны работать согласованно
joinUntilустанавливает крайний срок для группы- Закрытие scope всегда выполняет очистку
На этом курс по структурированному параллелизму завершён.
Часто задаваемые вопросы
Урок «Обработка ошибок и отмена» бесплатный?
Да — полный текст урока «Обработка ошибок и отмена» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Обработка ошибок и отмена»?
Корректно передавайте сведения о сбоях Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Обработка ошибок и отмена»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Модель структурированного параллелизма
- StructuredTaskScope
- Завершение при сбое и успехе
- Обработка ошибок и отмена