Spec-Zone.ru › OpenJDK 24

Класс StructuredTaskScope<T>

java.lang.Object
java.util.concurrent.StructuredTaskScope<T>
Параметры типа:
T - тип результата задач, выполняемых в области задач
Все реализованные интерфейсы:
AutoCloseable
Непосредственные известные подклассы:
StructuredTaskScope.ShutdownOnFailurePREVIEW, StructuredTaskScope.ShutdownOnSuccessPREVIEW
public class StructuredTaskScope<T> extends Object implements AutoCloseable
StructuredTaskScope — это предварительный API платформы Java.
Программы могут использовать StructuredTaskScope только при включенных предварительных функциях.
Предварительные функции могут быть удалены в будущей версии или обновлены до постоянных функций платформы Java.
Базовый API для структурированной конкурентности. StructuredTaskScope поддерживает случаи, когда задача разделяется на несколько конкурирующих подзадач, и подзадачи должны завершиться, прежде чем основная задача продолжится. StructuredTaskScope можно использовать для обеспечения того, что жизненный цикл конкурентной операции ограничен блоком синтаксиса, точно так же, как и последовательной операции в структурированном программировании.

Основные операции

StructuredTaskScope создается с помощью одного из своих публичных конструкторов. Он определяет метод fork для запуска потока для выполнения подзадачи, метод join для ожидания завершения всех подзадач и метод close для закрытия области задачи. API предназначен для использования с оператором try-with-resources. Цель состоит в том, чтобы код в блоке try использовал метод fork для создания потоков для выполнения подзадач, дождаться завершения подзадач с помощью метода join, а затем обработать результаты. Вызов метода fork возвращает SubtaskPREVIEW для представления вилки подзадачи. После вызова join, можно использовать Subtask для получения результата, если подзадача завершилась успешно, или исключение, если подзадача завершилась неудачно.
    Callable<String> task1 = ...
    Callable<Integer> task2 = ...

    try (var scope = new StructuredTaskScope<Object>()) {

        Subtask<String> subtask1 = scope.fork(task1);
        Subtask<Integer> subtask2 = scope.fork(task2);

        scope.join();

        ... process results/exceptions ...

    } // close

В следующем примере создается коллекция однородных подзадач, ожидает завершения всех подзадач с помощью метода join и использует Subtask.StatePREVIEW для разделения подзадач на набор подзадач, завершившихся успешно, и набор подзадач, завершившихся неудачно.

    List<Callable<String>> callables = ...

    try (var scope = new StructuredTaskScope<String>()) {

        List<Subtask<String>> subtasks = callables.stream().map(scope::fork).toList();

        scope.join();

        Map<Boolean, Set<Subtask<String>>> map = subtasks.stream()
                .collect(Collectors.partitioningBy(h -> h.state() == Subtask.State.SUCCESS,
                                                   Collectors.toSet()));

    } // close

Для обеспечения правильного использования методы join и close могут быть вызваны только владельцем (потоком, открывшим/создавшим область задачи), а метод close выбросит исключение после закрытия, если владелец не вызвал метод join после создания вилки.

StructuredTaskScope определяет метод shutdown для остановки области задачи без ее закрытия. Метод shutdown() прерывает все незавершенные подзадачи, прерывая потоки. Он предотвращает запуск новых потоков в области задачи. Если владелец ожидает в методе join, то он будет разбужен.

Остановка используется для короткого замыкания и позволяет подклассам реализовывать политики, не требующие завершения всех подзадач.

Подклассы с политиками для общих случаев

Определены два подкласса StructuredTaskScope для реализации политики для общих случаев:
  1. ShutdownOnSuccessPREVIEW захватывает результат первой подзадачи, завершившейся успешно. После захвата он останавливает область задачи, прерывает незавершенные потоки и будит владельца. Этот класс предназначен для случаев, когда результат любой подзадачи подходит ("вызвать любую") и нет необходимости ожидать результатов других незавершенных подзадач. Он определяет методы для получения первого результата или выброса исключения, если все подзадачи завершатся неудачно.
  2. ShutdownOnFailurePREVIEW захватывает исключение первой подзадачи, завершившейся неудачно. После захвата он останавливает область задачи, прерывает незавершенные потоки и будит владельца. Этот класс предназначен для случаев, когда результаты всех подзадач необходимы ("вызвать все"); если какая-либо подзадача завершится неудачно, результаты других незавершенных подзадач больше не нужны. Он определяет методы для выброса исключения, если какая-либо из подзадач завершится неудачно.

Ниже приведены два примера использования этих двух классов. В обоих случаях создается пара подзадач для получения ресурсов из двух URL-локаций "left" и "right". Первый пример создает объект ShutdownOnSuccess для захвата результата первой подзадачи, завершившейся успешно, прерывая другую с помощью остановки области задачи. Главная задача ожидает в join, пока либо подзадача завершится с результатом, либо обе подзадачи завершатся неудачно. Он вызывает метод result(Function)PREVIEW для получения полученного результата. Если обе подзадачи завершатся неудачно, этот метод выбросит WebApplicationException с исключением из одной из подзадач в качестве причины.

    try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {

        scope.fork(() -> fetch(left));
        scope.fork(() -> fetch(right));

        scope.join();

        String result = scope.result(e -> new WebApplicationException(e));

        ...
    }
Во втором примере создается объект ShutdownOnFailure для захвата исключения первой подзадачи, завершившейся неудачно, прерывая другую с помощью остановки области задачи. Главная задача ожидает в joinUntil(Instant), пока обе подзадачи завершатся с результатом, завершатся неудачно или будет достигнуто время завершения. Он вызывает throwIfFailed(Function)PREVIEW для выброса исключения, если какая-либо из подзадач завершится неудачно. Этот метод является бесполезным, если обе подзадачи завершатся успешно. В примере используется Supplier.get() для получения результата каждой подзадачи. Использование Supplier вместо Subtask предпочтительно в распространенных случаях, когда объект, возвращаемый fork, используется только для получения результата подзадачи, завершившейся успешно.
   Instant deadline = ...

   try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {

        Supplier<String> supplier1 = scope.fork(() -> query(left));
        Supplier<String> supplier2 = scope.fork(() -> query(right));

        scope.joinUntil(deadline);

        scope.throwIfFailed(e -> new WebApplicationException(e));

        // both subtasks completed successfully
        String result = Stream.of(supplier1, supplier2)
                .map(Supplier::get)
                .collect(Collectors.joining(", ", "{ ", " }"));

        ...
    }

Расширение StructuredTaskScope

StructuredTaskScope может быть расширена, а метод handleComplete переопределен для реализации других политик, кроме тех, что реализуются ShutdownOnSuccess и ShutdownOnFailure. Подкласс может, например, собирать результаты подзадач, завершившихся успешно, и игнорировать подзадачи, завершившиеся неудачно. Он может собирать исключения при неудачном завершении подзадач. Он может вызвать метод shutdown для остановки и заставить join проснуться, когда возникнет какое-либо условие.

Подкласс обычно определяет методы, чтобы сделать доступными результаты, состояние или другие результаты для кода, выполняемого после вызова метода join. Подкласс, который собирает результаты и игнорирует подзадачи, завершившиеся неудачно, может определить метод, возвращающий результаты. Подкласс, реализующий политику остановки при завершении подзадачи неудачно, может определить метод получения исключения первой подзадачи, завершившейся неудачно.

Ниже приведен пример простого StructuredTaskScope, который собирает однородные подзадачи, завершившиеся успешно. Он определяет метод "completedSuccessfully()", который основная задача может вызвать после присоединения.

    class CollectingScope<T> extends StructuredTaskScope<T> {
        private final Queue<Subtask<? extends T>> subtasks = new LinkedTransferQueue<>();

        @Override
        protected void handleComplete(Subtask<? extends T> subtask) {
            if (subtask.state() == Subtask.State.SUCCESS) {
                subtasks.add(subtask);
            }
        }

        @Override
        public CollectingScope<T> join() throws InterruptedException {
            super.join();
            return this;
        }

        public Stream<Subtask<? extends T>> completedSuccessfully() {
            super.ensureOwnerAndJoined();
            return subtasks.stream();
        }
    }

Реализация метода completedSuccessfully() в примере вызывает ensureOwnerAndJoined() для проверки, что метод может быть вызван только владельцем потока и только после того, как он присоединится.

Дерево структуры

Области задач образуют дерево, где родительско-потомок отношения устанавливаются неявно при открытии новой области задачи:
  • Отношение родитель-потомок устанавливается, когда поток, запущенный в области задачи, открывает свою собственную область задачи. Поток, запущенный в области задачи "A", открывающий область задачи "B", устанавливает отношение родитель-потомок, где область задачи "A" является родителем области задачи "B".
  • Отношение родитель-потомок устанавливается при вложенности. Если поток открывает область задачи "B", а затем открывает область задачи "C" (до закрытия "B"), то окружающая область задачи "B" является родителем вложенной области задачи "C".
Потомки области задачи — это области дочерних задач, которые она является родителем, плюс потомки дочерних областей задач рекурсивно.

Структура дерева поддерживает:

  • Наследование значений scoped values через потоки.
  • Проверки ограничения. Фраза "потоки, содержащиеся в области задачи", в описаниях методов означает потоки, запущенные в области задачи или дочерних областях задач.

Следующий пример демонстрирует наследование значения scoped value. Значение scoped value USERNAME привязано к значению "duke". Создается StructuredTaskScope и вызывается метод fork для запуска потока для выполнения childTask. Поток наследует привязки scoped value, захваченные при создании области задачи. Код в childTask использует значение scoped value и, таким образом, считывает значение "duke".

    private static final ScopedValue<String> USERNAME = ScopedValue.newInstance();

    ScopedValue.where(USERNAME, "duke").run(() -> {
        try (var scope = new StructuredTaskScope<String>()) {

            scope.fork(() -> childTask());
            ...
         }
    });

    ...

    String childTask() {
        String name = USERNAME.get();   // "duke"
        ...
    }

StructuredTaskScope в настоящее время не определяет API, которые раскрывают структуру дерева.

Если не указано иное, передача аргумента null в конструктор или метод в этом классе приведет к выбросу NullPointerException.

Последствия для согласованности памяти

Действия в потоке владельца или в потоке, содержащемся в области задачи, до создания вилки подзадачи fork предшествуют любым действиям, выполняемым этой подзадачей, которые, в свою очередь, предшествуют получению результата подзадачи retrievedPREVIEW или предшествуют любым действиям в потоке после присоединения join области задачи.

См. Спецификацию языка Java:
17.4.5 Порядок предшествования
С:
21

Краткое описание вложенных классов

Модификатор и тип Класс Описание
static final class  StructuredTaskScope.ShutdownOnFailurePREVIEW
Предварительный просмотр.
Объект StructuredTaskScope, который фиксирует исключение первой подзадачи, которая завершилась с ошибкой с ошибкойПРЕДПРОСМОТР.
static final class  StructuredTaskScope.ShutdownOnSuccessPREVIEW<T>
Предварительный просмотр.
Объект StructuredTaskScope, который фиксирует результат первой подзадачи, которая завершилась успешно успешноПРЕДПРОСМОТР.
static interface  StructuredTaskScope.SubtaskPREVIEW<T>
Предварительный просмотр.
Представляет подзадачу, созданную с помощью fork(Callable).

Краткое описание конструкторов

Конструктор Описание
StructuredTaskScope()
Создаёт безымянную область задач, которая создаёт виртуальные потоки.
StructuredTaskScope(String name, ThreadFactory factory)
Создаёт область задач с заданным именем и фабрикой потоков.

Краткое описание методов

Модификатор и тип Метод Описание
void close()
Закрывает эту область задач.
protected final void ensureOwnerAndJoined()
Убеждается, что текущий поток является владельцем этой области задач и что он присоединился (с помощью join() или joinUntil(Instant)) после создания подзадач.
<U extends T>
StructuredTaskScope.SubtaskPREVIEW<U>
fork(Callable<? extends U> task)
Запускает новый поток в этой области задач для выполнения задачи, возвращающей значение, тем самым создавая подзадачу этой области задач.
protected void handleComplete(StructuredTaskScope.SubtaskPREVIEW<? extends T> subtask)
Вызывается подзадачей при её успешном завершении или возникновении ошибки в этой области задач.
final boolean isShutdown()
Возвращает true, если эта область задач закрыта, иначе false.
StructuredTaskScopePREVIEW<T> join()
Ожидает завершения всех подзадач, запущенных в этой области задач, или закрытия области задач.
StructuredTaskScopePREVIEW<T> joinUntil(Instant deadline)
Ожидает завершения всех подзадач, запущенных в этой области задач, или закрытия области задач до указанного срока.
void shutdown()
Закрывает эту область задач без её закрытия.

Методы, объявленные в классе java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Подробное описание конструкторов

StructuredTaskScope

public StructuredTaskScope(String name, ThreadFactory factory)
Создает область задач со структурированным выполнением заданных именем и фабрикой потоков. Область задач, при необходимости, имеет имя для целей мониторинга и управления. Фабрика потоков используется для create потоков, когда подзадачи виртуального типа. Область задач принадлежит текущему потоку.

Создание фиксирует текущие привязки значений области видимости потока для наследования потоками, запущенными в области задач. Раздел Структура дерева в описании класса подробно описывает, как устанавливаются отношения родитель-ребенок неявно для целей наследования привязок значений области видимости.

Параметры:
name - имя области задач, может быть null
factory - фабрика потоков

StructuredTaskScope

public StructuredTaskScope()
Создает безымянную область задач со структурированным выполнением, которая создает виртуальные потоки. Область задач принадлежит текущему потоку.
Требования к реализации:
Этот конструктор эквивалентен вызову 2-аргументного конструктора с именем null и фабрикой потоков, которая создает виртуальные потоки.

Подробное описание методов

ensureOwnerAndJoined

protected final void ensureOwnerAndJoined()
Обеспечивает, что текущий поток является владельцем этой области задач и что он присоединился (с join() или joinUntil(Instant)) после создания подзадач.
Примечание API:
Этот метод может использоваться подклассами, которые определяют методы для предоставления результатов, состояния или других результатов коду, предназначенному для выполнения после метода присоединения.
Исключения:
WrongThreadException - если текущий поток не является владельцем области задач
IllegalStateException - если область задач открыта, а владелец области задач не присоединился после создания подзадач

handleComplete

protected void handleComplete(StructuredTaskScope.SubtaskPREVIEW<? extends T> subtask)
Вызывается подзадачей при успешном завершении или ошибке в этой области задач. Этот метод не вызывается, если подзадача завершается после того, как область задач завершается.
Примечание API:
Метод handleComplete должен быть потокобезопасен. Он может вызываться несколькими потоками одновременно.
Требования к реализации:
Реализация по умолчанию вызывает NullPointerException, если подзадача null. Она вызывает IllegalArgumentException, если подзадача не завершена.
Параметры:
subtask - подзадача
Исключения:
IllegalArgumentException - если вызван с подзадачей, которая не завершена

fork

public <U extends T> StructuredTaskScope.SubtaskPREVIEW<U> fork(Callable<? extends U> task)
Запускает новый поток в этой области задач для выполнения задачи, возвращающей значение, тем самым создавая подзадачу этой области задач.

Задача, возвращающая значение, предоставляется этому методу как Callable, поток выполняет метод call задачи. Поток создается с помощью ThreadFactory области задач. Он наследует текущие привязки значений области видимости потока. Привязки должны соответствовать привязки, захваченные при создании области задач.

Этот метод возвращает SubtaskПРОСМОТР для представления подзадачи. Объект Subtask может использоваться для получения результата, когда подзадача завершается успешно, или исключения, когда подзадача завершается ошибкой. Для обеспечения правильного использования методы get()ПРОСМОТР и exception()ПРОСМОТР могут вызываться только владельцем области задач после ожидания завершения всех потоков с помощью методов join или joinUntil(Instant). Когда подзадача завершается, поток вызывает метод handleComplete для обработки завершенной подзадачи. Если область задач завершается перед завершением подзадачи, то метод handleComplete не будет вызван.

Если эта область задач завершается (или в процессе завершения), то подзадача не будет запущена, и метод handleComplete не будет вызван.

Этот метод может вызываться только владельцем области задач или потоками, содержащимися в области задач.

Требования к реализации:
Этот метод может быть переопределен для целей настройки, например, для обертывания задач. Если переопределен, подкласс должен вызвать super.fork, чтобы запустить новый поток в этой области задач.
Параметры типа:
U - тип результата
Параметры:
task - задача, возвращающая значение, для выполнения потоком
Возвращает:
подзадача
Исключения:
IllegalStateException - если эта область задач закрыта
WrongThreadException - если текущий поток не является владельцем области задач или потоком, содержащимся в области задач
StructureViolationExceptionPREVIEW - если текущие привязки значений области видимости не такие же, как при создании области задач
RejectedExecutionException - если фабрика потоков отклонила создание потока для выполнения подзадачи

join

public StructuredTaskScopePREVIEW<T> join() throws InterruptedException
Ожидает завершения всех подзадач, запущенных в этой области задач, или завершения области задач.

Этот метод ожидает всех подзадач, ожидая завершения всех потоков запущенных в этой области задач. Он перестает ожидать, когда все потоки завершаются, область задач завершается, или текущий поток прерывается.

Этот метод может вызываться только владельцем области задач.

Требования к реализации:
Этот метод может быть переопределен для целей настройки или для возвращения более специфического типа возвращаемого значения. Если переопределен, подкласс должен вызвать super.join, чтобы гарантировать, что метод ожидает завершения потоков в этой области задач.
Возвращает:
эта область задач
Исключения:
IllegalStateException - если эта область задач закрыта
WrongThreadException - если текущий поток не является владельцем области задач
InterruptedException - если прервано во время ожидания

joinUntil

public StructuredTaskScopePREVIEW<T> joinUntil(Instant deadline) throws InterruptedException, TimeoutException
Ожидает завершения всех подзадач, запущенных в этой области задач, или завершения области задач до указанного момента.

Этот метод ожидает всех подзадач, ожидая завершения всех потоков запущенных в этой области задач. Он перестает ожидать, когда все потоки завершаются, область задач завершается, достигается крайний срок, или текущий поток прерывается.

Этот метод может вызываться только владельцем области задач.

Требования к реализации:
Этот метод может быть переопределен для целей настройки или для возвращения более специфического типа возвращаемого значения. Если переопределен, подкласс должен вызвать super.joinUntil, чтобы гарантировать, что метод ожидает завершения потоков в этой области задач.
Параметры:
deadline - крайний срок
Возвращает:
эта область задач
Исключения:
IllegalStateException - если эта область задач закрыта
WrongThreadException - если текущий поток не является владельцем области задач
InterruptedException - если прервано во время ожидания
TimeoutException - если крайний срок достигнут во время ожидания

shutdown

public void shutdown()
Остановите этот контекст задачи, не закрывая его. Остановка контекста задачи предотвращает запуск новых потоков, прерывает все незавершенные потоки и вызывает пробуждение метода join. Остановка полезна в тех случаях, когда результаты незавершенных подзадач больше не нужны. Обычно она вызывается реализацией handleComplete(Subtask) подкласса, который реализует политику отбрасывания незавершенных задач после достижения некоторого результата.

Более конкретно, этот метод:

  • Прерывает все незавершенные потоки в контексте задачи (кроме текущего потока).
  • Пробуждает владельца контекста задачи, если он ожидает в методе join() или joinUntil(Instant). Если владелец контекста задачи не ожидает, то его следующий вызов join или joinUntil вернет результат немедленно.

Состояние незавершенных подзадач, которые завершаются примерно в момент остановки контекста задачи, не определено. Подзадача, которая успешно завершается с результатом или завершается с исключением примерно в момент остановки контекста задачи, может или не может перейти в терминальное состояние.

Этот метод может быть вызван только владельцем контекста задачи или потоками, содержащимися в контексте задачи.

API Note:
Возможны потоки, которые не завершены, потому что они выполняют код, который не отреагировал (или не отреагировал быстро) на прерывание потока. Этот метод не ожидает этих потоков. Когда владелец вызывает метод close для закрытия контекста задачи, он будет ждать завершения оставшихся потоков.
Implementation Requirements:
Этот метод может быть переопределен для настройки. При переопределении подкласс должен вызвать super.shutdown, чтобы гарантировать остановку контекста задачи.
Throws:
IllegalStateException - если этот контекст задачи закрыт
WrongThreadException - если текущий поток не является владельцем контекста задачи или потоком, содержащимся в контексте задачи
See Also:
  • isShutdown()

isShutdown

public final boolean isShutdown()
Возвращает true, если этот контекст задачи остановлен, иначе false.
Returns:
true, если этот контекст задачи остановлен, иначе false
See Also:
  • shutdown()

close

public void close()
Закрывает этот контекст задачи.

Этот метод сначала останавливает контекст задачи (как если бы вызов метода shutdown). Затем он ожидает завершения потоков, выполняющих любые незавершенные задачи. Если прерван, этот метод продолжит ожидать завершения потоков перед завершением с установленным статусом прерывания.

Этот метод может быть вызван только владельцем контекста задачи. Если контекст задачи уже закрыт, то вызов этого метода владельцем контекста задачи не оказывает никакого эффекта.

Контекст задач предназначен для использования в структурированном формате. Если этот метод вызывается для закрытия контекста задачи до закрытия вложенных контекстов задач, то он закрывает базовую структуру каждого вложенного контекста задачи (в обратном порядке их создания), закрывает этот контекст задачи и затем выводит StructureViolationExceptionPREVIEW. Аналогично, если этот метод вызывается для закрытия контекста задачи во время выполнения со связыванием привязок значений с областью видимости, и контекст задачи был создан до привязки значений с областью видимости, то StructureViolationException генерируется после закрытия контекста задачи. Если поток завершается без предварительного закрытия контекстов задач, которыми он владеет, то завершение вызовет закрытие базовой структуры каждой из открытых задач контекстов. Закрытие выполняется в обратном порядке создания контекстов задач. Поэтому завершение потока может быть отложено, когда владельцу контекста задачи необходимо дождаться завершения потоков, созданных в этих контекстах задач.

Specified by:
close в интерфейсе AutoCloseable
Implementation Requirements:
Этот метод может быть переопределен для настройки. При переопределении подкласс должен вызвать super.close для закрытия контекста задачи.
Throws:
IllegalStateException - выводится после закрытия контекста задачи, если владелец контекста задачи не пытался присоединиться после расщепления
WrongThreadException - если текущий поток не является владельцем контекста задачи
StructureViolationExceptionPREVIEW - если было обнаружено нарушение структуры

© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://download.java.net/java/early_access/jdk24/docs/api/java.base/java/util/concurrent/StructuredTaskScope.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API