0Pricing
Java Academy · Урок

Обработка ошибок и отмена

Корректно передавайте сведения о сбоях

«Обработка ошибок и отмена» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Модель структурированного параллелизма
  2. StructuredTaskScope
  3. Завершение при сбое и успехе
  4. Обработка ошибок и отмена
← Назад к Java Academy