Завершение при сбое и успехе
Координируйте результаты задач
«Завершение при сбое и успехе» — бесплатный урок Java Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Два распространённых шаблона
Большинство параллельных разветвлений относится к одному из двух вариантов:
- Все должны завершиться успешно: если одна подзадача завершается с ошибкой, остальные прекращаются. Используйте
ShutdownOnFailure. - Побеждает первая: как только одна подзадача завершается успешно, остальные отменяются. Используйте
ShutdownOnSuccess.
JDK предоставляет оба варианта из коробки.
Идея ShutdownOnFailure
ShutdownOnFailure предназначена для задач, которые все должны завершиться успешно, например для совместного получения профиля пользователя и его заказов.
Если одна подзадача выбрасывает исключение, scope отменяет остальные, чтобы не тратить ресурсы впустую.
Пример ShutdownOnFailure
После join() вызывается throwIfFailed(), который повторно выбрасывает первую ошибку, если она произошла, оборачивая её в ExecutionException.
import java.util.concurrent.StructuredTaskScope;
public class Main {
public static void main(String[] args) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
var a = scope.fork(() -> fetch("profile"));
var b = scope.fork(() -> fetch("orders"));
scope.join();
scope.throwIfFailed();
System.out.println(a.get() + " + " + b.get());
}
}
static String fetch(String what) {
return what + "-ok";
}
}Что делает throwIfFailed
throwIfFailed() проверяет подзадачи. Если все завершились успешно, он ничего не делает. Если какая-либо завершилась с ошибкой, он выбрасывает исключение, оборачивая исходное исключение.
Также можно передать функцию, преобразующую причину в собственный тип исключения.
Идея ShutdownOnSuccess
ShutdownOnSuccess предназначена для резервирования или гонки: запросите несколько зеркал и возьмите ответившее первым.
В момент успешного завершения одной подзадачи scope отменяет остальные и сохраняет победивший результат.
Пример ShutdownOnSuccess
Победившее значение получают с помощью result(). Этот вызов выбрасывает исключение, если ни одна подзадача не завершилась успешно.
import java.util.concurrent.StructuredTaskScope;
public class Main {
public static void main(String[] args) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
scope.fork(() -> queryMirror("eu"));
scope.fork(() -> queryMirror("us"));
scope.join();
System.out.println("Fastest answer: " + scope.result());
}
}
static String queryMirror(String region) {
return region + "-data";
}
}Результат против get
Обратите внимание на различие:
ShutdownOnFailure: прочитайте каждую подзадачу с помощью собственногоget()ShutdownOnSuccess: прочитайте единственного победителя с помощьюresult()scope
Отмена выполняется согласованно
Когда scope завершает работу, он прерывает потоки оставшихся подзадач. Корректно написанные задачи проверяют факт прерывания и быстро останавливаются.
Блокирующие вызовы стандартной библиотеки обычно автоматически реагируют на прерывание.
join с ограничением времени
Обе политики поддерживают крайний срок. Вызов joinUntil(Instant) ожидает только до определённого момента, затем выбрасывает TimeoutException и завершает работу scope.
Выбор политики
Задайте себе один вопрос: нужны ли мне все результаты или только первый?
- Все результаты, быстро завершить работу при ошибке:
ShutdownOnFailure - Любой один результат, побеждает самый быстрый:
ShutdownOnSuccess
Для остальных случаев создайте подкласс StructuredTaskScope.
Пользовательские политики
Можно расширить StructuredTaskScope и переопределить handleComplete(Subtask), чтобы реализовать особые правила, например собирать первые N успешных результатов или завершать работу после заданного числа ошибок.
Быстрая проверка
Сопоставьте сценарий с политикой.
Итоги
Вы изучили две встроенные политики завершения:
ShutdownOnFailure+throwIfFailed+ отдельныйgetдля каждой подзадачи, если все должны завершиться успешноShutdownOnSuccess+resultдля варианта, где побеждает первая успешная подзадача- Завершение работы согласованно прерывает оставшиеся подзадачи
joinUntilдобавляет крайние сроки, а создание подкласса — пользовательские правила
Далее: подробное рассмотрение обработки ошибок и отмены.
Часто задаваемые вопросы
Урок «Завершение при сбое и успехе» бесплатный?
Да — полный текст урока «Завершение при сбое и успехе» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Завершение при сбое и успехе»?
Координируйте результаты задач Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Завершение при сбое и успехе»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Модель структурированного параллелизма
- StructuredTaskScope
- Завершение при сбое и успехе
- Обработка ошибок и отмена