Spec-Zone.ru › OpenJDK 27

Интерфейс StructuredTaskScope<T, R, R_X extends Throwable>

Параметры типа:
T — тип результата подзадач, запущенных в области
R — тип результата, возвращаемого методом join()
R_X — тип исключения, выбрасываемого методом join()
Все суперинтерфейсы:
AutoCloseable
public sealed interface StructuredTaskScope<T, R, R_X extends Throwable> extends AutoCloseable
StructuredTaskScope — это предварительная версия API платформы Java.
Программы могут использовать StructuredTaskScope только при включённых предварительных функциях.
Предварительные функции могут быть удалены в одном из следующих выпусков или стать постоянными функциями платформы Java.
API для структурированной конкурентности. StructuredTaskScope поддерживает случаи, когда выполнение задачи (единицы работы) разбивается на несколько выполняющихся одновременно подзадач, которые должны завершиться до продолжения задачи. StructuredTaskScope можно использовать, чтобы ограничить время жизни конкурентной операции синтаксическим блоком, подобно тому, как это делается для последовательной операции в структурном программировании.

StructuredTaskScope определяет статический метод open() для создания и открытия новой StructuredTaskScope. Он определяет метод close() для её закрытия. API предназначен для использования с оператором try-with-resources, в котором StructuredTaskScope открывается как ресурс, а затем закрывается автоматически. Код внутри блока try использует метод fork(Callable), чтобы запускать подзадачи. Каждый вызов метода fork(Callable) запускает новый Thread (обычно виртуальный поток) для выполнения подзадачи в виде метода, возвращающего значение. Подзадача выполняется одновременно с кодом внутри блока try и с другими подзадачами, запущенными в области. Запустив все подзадачи, код внутри блока использует метод join(), чтобы дождаться завершения всех подзадач (или другого исхода) как единой операции. Код после метода join() обрабатывает результат. Выполнение не продолжается за пределами блока try (или метода close), пока не завершатся все потоки, запущенные в области для выполнения подзадач.

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

Для начала рассмотрим пример: задача «main» разбивается на две подзадачи, которые параллельно получают значения от двух удалённых служб. Главная задача объединяет результаты обеих подзадач. В примере вызывается fork(Callable) для запуска двух подзадач. Каждый вызов fork(Callable) возвращает Subtask в качестве дескриптора запущенной подзадачи. Обе подзадачи могут завершиться успешно, одна подзадача может завершиться успешно, а другая — с ошибкой, или обе подзадачи могут завершиться с ошибкой.

Главная задача в примере заинтересована в успешном результате обеих подзадач. В методе join() она ожидает успешного завершения обеих подзадач или сбоя любой из них. Если обе подзадачи завершатся успешно, метод join() завершится нормально, и задача использует метод Subtask.get()PREVIEW, чтобы получить результат каждой подзадачи. Если одна из подзадач завершится с ошибкой, другая подзадача будет отменена, а метод join() выбросит ExecutionException, указав исключение от сбойной подзадачи в качестве причины.

   try (var scope = StructuredTaskScope.open()) {

       Subtask<String> subtask1 = scope.fork(() -> fetchFromRemoteService1());
       Subtask<Integer> subtask2 = scope.fork(() -> fetchFromRemoteService2());

       // throws ExecutionException if either subtask fails
       scope.join();

       // both subtasks completed successfully
       var result = new MyResult(subtask1.get(), subtask2.get());

   } // close

Метод close() всегда ожидает завершения потоков, выполняющих подзадачи, даже если метод join() выбрасывает исключение, поэтому выполнение не может продолжиться за пределами метода close(), пока прерванные потоки не завершатся.

Чтобы обеспечить возможность отмены, подзадачи должны быть написаны так, чтобы при прерывании они завершались как можно скорее. Подзадачи, которые не реагируют на прерывание, например блокируются на методах, не поддерживающих прерывание, могут задержать выполнение метода close() на неопределённое время.

В примере подзадачи возвращают результаты разных типов (String и Integer). В других случаях все подзадачи могут возвращать результаты одного типа. Если бы в примере для открытия области использовался StructuredTaskScope.<String>open(), то его можно было бы использовать только для запуска подзадач, возвращающих результат String.

Объединители

В приведённом выше примере метод join() завершается нормально и возвращает null, если все подзадачи выполнены успешно. Если какая-либо подзадача завершается с ошибкой, он выбрасывает ExecutionException. Другие политики и результаты можно получить, создав StructuredTaskScope с помощью JoinerPREVIEW, реализующего требуемую политику и результат. Joiner обрабатывает подзадачи при их запуске и завершении и формирует результат для метода join(). Вместо null, Joiner может привести к тому, что join() вернёт результат конкретной подзадачи, коллекцию результатов или объект, созданный на основе результатов некоторых или всех подзадач. Если результатом является исключение, Joiner может привести к тому, что join() выбросит исключение, отличное от ExecutionException.

Joiner может отменить область (иногда это называют «досрочным завершением»), когда выполнено некоторое условие, например сбой подзадачи, и результат остальных выполняющихся подзадач уже не требуется. Отмена области не позволяет запускать в ней новые потоки, отменяет подзадачи, выполнение которых ещё не завершено, и пробуждает метод join() с результатом (значением или исключением). В приведённом выше примере результатом является нормальное завершение join(), когда все подзадачи выполнены успешно. Область отменяется, если любая подзадача завершается с ошибкой, а join() выбрасывает ExecutionException, указывая исключение от сбойной подзадачи в качестве причины. Другие реализации Joiner могут отменять область по другим причинам и приводить к тому, что join() выбрасывает другое исключение, если результатом является исключение.

Интерфейс JoinerPREVIEW определяет статические фабричные методы для создания Joiner для ряда распространённых случаев. Если требуется более сложная или пользовательская политика, можно реализовать этот интерфейс. Joiner, возвращающий результат, отличный от null, может избавить от необходимости вести учёт и хранить ссылки на объекты Subtask, возвращаемые методом fork(Callable).

Рассмотрим другой пример, в котором главная задача разбивается на две подзадачи. В этом примере каждая подзадача возвращает результат String, а главной задаче нужен только результат первой успешно завершившейся подзадачи. В примере используется Joiner.anySuccessfulOrThrow()PREVIEW для создания Joiner, возвращающего результат любой успешно завершившейся подзадачи.

   try (var scope = StructuredTaskScope.open(Joiner.<String>anySuccessfulOrThrow())) {

       scope.fork(callable1);
       scope.fork(callable2);

       // throws ExecutionException if both subtasks fail
       String firstResult = scope.join();

   } // close

В примере задача запускает две подзадачи, а затем в методе join() ожидает успешного завершения любой из них или сбоя обеих. Если одна из подзадач завершится успешно, Joiner вызовет отмену другой подзадачи (поток, выполняющий её, будет прерван), а метод join() вернёт результат успешно завершившейся подзадачи. Отмена другой подзадачи позволяет задаче не ожидать результат, который ей не нужен. Если обе подзадачи завершатся с ошибкой, метод join() выбросит ExecutionException, указав исключение одной из подзадач в качестве причины. Joiner.anySuccessfulOrThrow(Function)PREVIEW можно использовать с функцией, которая при сбое всех подзадач создаёт исключение, отличное от ExecutionException.

Конфигурация

StructuredTaskScope открывается с конфигурацией, состоящей из ThreadFactory для создания потоков, необязательного имени области и необязательного времени ожидания. Имя предназначено для мониторинга и управления.

Методы open() и open(Joiner) создают StructuredTaskScope с конфигурацией по умолчанию. Конфигурация по умолчанию содержит ThreadFactory, создающий безымянные виртуальные потоки; область не получает имени, и время ожидания не задаётся.

Методы open(UnaryOperator) и open(Joiner, UnaryOperator) можно использовать для создания StructuredTaskScope с другим ThreadFactory, именем для мониторинга и управления или временем ожидания, при истечении которого область отменяется, если это происходит до или во время ожидания завершения подзадач. Методы open принимают оператор, применяемый к конфигурации по умолчанию и возвращающий ConfigurationPREVIEW для создаваемой StructuredTaskScope.

В следующем примере открывается новая StructuredTaskScope с ThreadFactory, создающей виртуальные потоки с именами "duke-0", "duke-1" ...

    ThreadFactory factory = Thread.ofVirtual().name("duke-", 0).factory();

    try (var scope = StructuredTaskScope.open(cf -> cf.withThreadFactory(factory))) {

        var subtask1 = scope.fork( .. );   // runs in a virtual thread with name "duke-0"
        var subtask2 = scope.fork( .. );   // runs in a virtual thread with name "duke-1"

        scope.join();

        var result = new MyResult(subtask1.get(), subtask2.get());

     }

Во втором примере задаётся время ожидания, представленное объектом Duration. Отсчёт времени ожидания начинается при открытии новой области. Если время ожидания истечёт до или во время ожидания в методе join(), область будет отменена (потоки, выполняющие незавершённые подзадачи, будут прерваны), а метод join() выбросит ExecutionException, указав в качестве причины CancelledByTimeoutExceptionPREVIEW.

   Duration timeout = Duration.ofSeconds(10);

   try (var scope = StructuredTaskScope.open(Joiner.<String>allSuccessfulOrThrow(),
                                             cf -> cf.withTimeout(timeout))) {

       scope.fork(callable1);   // subtask takes a really long time
       scope.fork(callable2);

       // throws ExecutionException with CancelledByTimeoutException as cause
       List<String> results = scope.join();

   }

Обработка исключений

Результатом метода join() является значение или исключение. Если результатом является исключение, его причиной обычно будет исключение от сбойной подзадачи или CancelledByTimeoutExceptionPREVIEW, если было задано время ожидания.

В некоторых случаях может быть полезно добавить блок catch к оператору try-with-resources для обработки исключения. В следующем примере метод open(UnaryOperator) используется для открытия области с заданным временем ожидания. Метод join() в этом примере выбрасывает ExecutionException, если какая-либо подзадача завершится с ошибкой или истечёт время ожидания. Причиной исключения будет исключение от сбойной подзадачи или CancelledByTimeoutException. В примере оператор switch используется для выбора действия в зависимости от причины.

   try (var scope = StructuredTaskScope.open(cf -> cf.withTimeout(timeout))) {

       ..

   } catch (ExecutionException e) {
       switch (e.getCause()) {
           case CancelledByTimeoutException ->
           case IOException ioe -> ..
           default -> ..
       }
   }

В других случаях перехватывать исключение может быть нецелесообразно: его можно передать настроенному обработчику неперехваченных исключений для журналирования.

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

Метод join() выбрасывает InterruptedException, если поток прерван до или во время ожидания в методе join(). Раздел Thread Interruption спецификации Thread содержит рекомендации по обработке этого исключения.

Наследование привязок ограниченных значений

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

При использовании вместе с StructuredTaskScope, ScopedValue также может безопасно и эффективно передавать значение методам, выполняемым подзадачами, запущенными в области. Когда объект ScopedValue привязан к значению в потоке, выполняющем главную задачу, эта привязка наследуется потоками, созданными для выполнения подзадач. Поток, выполняющий главную задачу, не продолжает выполнение за пределами метода close(), пока не завершатся все потоки, выполняющие подзадачи. Это гарантирует, что ScopedValue не станет непривязанным (или не вернётся к предыдущему значению), пока выполняются подзадачи. Помимо безопасного и эффективного способа наследования значения подзадачами, это наследование позволяет преобразовать последовательный код, использующий ScopedValue, в код со структурированной конкурентностью.

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

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

В следующем примере демонстрируется наследование привязок ограниченных значений. Ограниченное значение USERNAME привязано к значению "duke" на ограниченный период выполнения лямбда-выражения потоком, который его выполняет. Код в блоке открывает StructuredTaskScope и запускает две подзадачи, а затем ожидает в методе join() и объединяет результаты обеих подзадач. Если код, выполняемый потоками, в которых запущены subtask1 и subtask2, использует ScopedValue.get() для получения значения USERNAME, то будет возвращено значение "duke".

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

    MyResult result = ScopedValue.where(USERNAME, "duke").call(() -> {

        try (var scope = StructuredTaskScope.open()) {

            Subtask<String> subtask1 = scope.fork( .. );    // inherits binding
            Subtask<Integer> subtask2 = scope.fork( .. );   // inherits binding

            scope.join();
            return new MyResult(subtask1.get(), subtask2.get());
        }

    });

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

Подзадача может выполнять код, который сам открывает новую StructuredTaskScope. Главная задача, выполняющаяся в потоке T1, открывает StructuredTaskScope и запускает подзадачу, выполняющуюся в потоке T2. Привязки ограниченных значений, сохранённые при открытии области потоком T1, наследуются потоком T2. Подзадача (в потоке T2) выполняет код, который открывает новую StructuredTaskScope и запускает (под-)подзадачу, выполняющуюся в потоке T3. Привязки ограниченных значений, сохранённые при открытии области потоком T2, наследуются потоком T3. В их число входят привязки, унаследованные от T1. Таким образом, ограниченные значения наследуются по дереву подзадач, а не только на один уровень вложенности.

Гарантии согласованности памяти

Действия в потоке-владельце StructuredTaskScope, выполненные до запуска подзадачи, происходят-перед любыми действиями потока, выполняющего подзадачу; в свою очередь, они происходят-перед действиями любого потока, который успешно получает результат подзадачи с помощью Subtask.get()PREVIEW или Subtask.exception()PREVIEW. Если результат подзадачи влияет на значение или исключение, возвращаемое методом join(), то любые действия потока, выполняющего эту подзадачу, происходят-перед возвратом потока-владельца из join() с результатом.

Общие исключения

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

См. Спецификацию языка Java:
17.4.5 Порядок «происходит-перед»
Начиная с версии:
21

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

Модификатор и тип Интерфейс Описание
static final class  StructuredTaskScope.CancelledByTimeoutExceptionPREVIEW
Предварительная версия.
Причина исключения, которое выбрасывает join() при отмене области из-за истечения времени ожидания.
static interface  StructuredTaskScope.ConfigurationPREVIEW
Предварительная версия.
Представляет конфигурацию для StructuredTaskScope.
static interface  StructuredTaskScope.JoinerPREVIEW<T, R, R_X extends Throwable>
Предварительная версия.
Объект, используемый с StructuredTaskScopePREVIEW для формирования результата области для её метода join().
static interface  StructuredTaskScope.SubtaskPREVIEW<T>
Предварительная версия.
Представляет подзадачу, запущенную в StructuredTaskScopePREVIEW с помощью fork(Callable) или fork(Runnable).

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

Модификатор и тип Метод Описание
void close()
Закрывает эту область.
<U extends T>
StructuredTaskScope.SubtaskPREVIEW<U>
fork(Runnable task)
Запускает подзадачу, создавая в этой области новый поток для выполнения метода, не возвращающего результат.
<U extends T>
StructuredTaskScope.SubtaskPREVIEW<U>
fork(Callable<? extends U> task)
Запускает подзадачу, создавая в этой области новый поток для выполнения метода, возвращающего значение.
boolean isCancelled()
Возвращает true, если эта область отменена или отменяется, в противном случае — false.
R join()
Возвращает результат или выбрасывает исключение после ожидания завершения всех подзадач либо отмены области.
static <T> StructuredTaskScopePREVIEW<T, Void, ExecutionException> open()
Открывает новую StructuredTaskScope, в которой метод join() ожидает успешного завершения всех подзадач или сбоя любой из них.
static <T, R, R_X extends Throwable>
StructuredTaskScopePREVIEW<T,R,R_X>
open(StructuredTaskScope.JoinerPREVIEW<? super T, ? extends R, R_X> joiner)
Открывает новую StructuredTaskScope, использующую заданный объект Joiner.
static <T, R, R_X extends Throwable>
StructuredTaskScopePREVIEW<T,R,R_X>
open(StructuredTaskScope.JoinerPREVIEW<? super T, ? extends R, R_X> joiner, UnaryOperator<StructuredTaskScope.ConfigurationPREVIEW> configOperator)
Открывает новую StructuredTaskScope, использующую заданный объект Joiner и Configuration, полученную применением заданного оператора к конфигурации по умолчанию.
static <T> StructuredTaskScopePREVIEW<T, Void, ExecutionException> open(UnaryOperator<StructuredTaskScope.ConfigurationPREVIEW> configOperator)
Открывает новую StructuredTaskScope, использующую Configuration, полученную применением заданного оператора к конфигурации по умолчанию.

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

open

static <T, R, R_X extends Throwable> StructuredTaskScopePREVIEW<T,R,R_X> open(StructuredTaskScope.JoinerPREVIEW<? super T, ? extends R, R_X> joiner, UnaryOperator<StructuredTaskScope.ConfigurationPREVIEW> configOperator)
Открывает новую StructuredTaskScope, использующую заданный объект Joiner и Configuration, полученную в результате применения заданного оператора к конфигурации по умолчанию.

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

Этот метод вызывает метод apply оператора с конфигурацией по умолчанию, чтобы получить конфигурацию для новой области видимости:

  • Если метод apply возвращает Configuration с ThreadFactory, заданной с помощью withThreadFactory(ThreadFactory)ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ, ее метод newThread(Runnable) будет вызван для создания потоков при запуске подзадач в области видимости. Если ThreadFactory не задана, для каждой подзадачи при запуске будет создан безымянный виртуальный поток.
  • Если метод apply возвращает Configuration с тайм-аутом, заданным с помощью withTimeout(Duration)ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ, отсчет тайм-аута начнется при открытии области видимости. Если тайм-аут истечет до начала или во время ожидания в методе join(), область видимости будет отменена. От того, какой именно Joiner используется, зависит, вернет ли метод join() результат или выбросит исключение при истечении тайм-аута. Если результатом будет исключение, оно будет выброшено с CancelledByTimeoutExceptionПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ в качестве причины.
  • Если метод apply возвращает Configuration с именем, заданным с помощью withName(String)ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ, это имя будет использоваться для мониторинга и управления.
  • Если метод apply выбрасывает исключение или ошибку, они передаются этим методом дальше.
  • Если метод apply возвращает null, выбрасывается NullPointerException.

Новая область видимости принадлежит текущему потоку. Только код, выполняющийся в этом потоке, может выполнять fork, join или close для этой области видимости.

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

Параметры типа:
T — тип результата подзадач, запущенных в этой области видимости
R — тип результата, возвращаемого методом join()
R_X — тип исключения, выбрасываемого методом join()
Параметры:
joiner — объект Joiner
configOperator — оператор для получения конфигурации
Возвращает:
новую область видимости
Начиная с версии:
26

open

static <T, R, R_X extends Throwable> StructuredTaskScopePREVIEW<T,R,R_X> open(StructuredTaskScope.JoinerPREVIEW<? super T, ? extends R, R_X> joiner)
Открывает новую StructuredTaskScope, использующую заданный объект Joiner. Joiner реализует требуемую политику и формирует результат (значение или исключение) для метода join(), когда все подзадачи, запущенные в области видимости, завершат выполнение или область видимости будет отменена.

Область видимости создается с конфигурацией по умолчанию. Конфигурация по умолчанию содержит ThreadFactory, создающую безымянные виртуальные потоки, не задает имя области видимости и не содержит тайм-аута.

Новая область видимости принадлежит текущему потоку. Только код, выполняющийся в этом потоке, может выполнять fork, join или close для этой области видимости.

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

Требования к реализации:
Этот фабричный метод эквивалентен вызову метода open с двумя аргументами с заданным Joiner и тождественным оператором.
Параметры типа:
T — тип результата подзадач, запущенных в этой области видимости
R — тип результата, возвращаемого методом join()
R_X — тип исключения, выбрасываемого методом join()
Параметры:
joiner — объект Joiner
Возвращает:
новую область видимости
Начиная с версии:
25

open

static <T> StructuredTaskScopePREVIEW<T, Void, ExecutionException> open(UnaryOperator<StructuredTaskScope.ConfigurationPREVIEW> configOperator)
Открывает новую StructuredTaskScope, использующую Configuration, полученную в результате применения заданного оператора к конфигурации по умолчанию. Этот метод вызывает метод apply оператора для получения конфигурации новой области видимости, как указано в методе open с двумя аргументами.

Метод join() новой области видимости ожидает успешного завершения всех подзадач или сбоя любой подзадачи. join() method возвращает null, если все подзадачи завершились успешно. Он выбрасывает ExecutionException, если какая-либо подзадача завершилась с ошибкой; причиной будет исключение первой завершившейся с ошибкой подзадачи (причина). Если задан тайм-аутПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ и он истекает до начала или во время ожидания в методе join(), метод выбрасывает ExecutionException с CancelledByTimeoutExceptionПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ в качестве причины.

Новая область видимости принадлежит текущему потоку. Только код, выполняющийся в этом потоке, может выполнять fork, join или close для этой области видимости.

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

Требования к реализации:
Этот фабричный метод эквивалентен вызову метода open с двумя аргументами с объектом Joiner, созданным с помощью awaitAllSuccessfulOrThrow()ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ, и заданным оператором конфигурации.
Параметры типа:
T — тип результата подзадач, запущенных в этой области видимости
Параметры:
configOperator — оператор для получения конфигурации
Возвращает:
новую область видимости
Начиная с версии:
27

open

static <T> StructuredTaskScopePREVIEW<T, Void, ExecutionException> open()
Открывает новую StructuredTaskScope, в которой метод join() ожидает успешного завершения всех подзадач или сбоя любой подзадачи. Метод join() возвращает null, если все подзадачи завершились успешно. Он выбрасывает ExecutionException, если какая-либо подзадача завершилась с ошибкой; причиной будет исключение первой завершившейся с ошибкой подзадачи (причина).

Область видимости создается с конфигурацией по умолчанию. Конфигурация по умолчанию содержит ThreadFactory, создающую безымянные виртуальные потоки, не задает имя области видимости и не содержит тайм-аута.

Новая область видимости принадлежит текущему потоку. Только код, выполняющийся в этом потоке, может выполнять fork, join или close для этой области видимости.

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

Требования к реализации:
Этот фабричный метод эквивалентен вызову метода open с двумя аргументами с объектом Joiner, созданным с помощью awaitAllSuccessfulOrThrow()ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ, и тождественным оператором.
Параметры типа:
T — тип результата подзадач
Возвращает:
новую область видимости
Начиная с версии:
25

fork

<U extends T> StructuredTaskScope.SubtaskPREVIEW<U> fork(Callable<? extends U> task)
Запускает подзадачу, создавая в этой области видимости новый поток для выполнения метода, возвращающего значение. Новый поток выполняет подзадачу параллельно с текущим потоком. Параметр этого метода — Callable; новый поток выполняет его метод call(). Поток наследует привязки ограниченных значений текущего потока, которые должны совпадать с привязками, зафиксированными при открытии области видимости.

Если область видимости была открыта с функцией для получения ConfigurationПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ этой области видимости и задана ThreadFactory, то для создания потока, который выполнит подзадачу, вызывается ее метод newThread(Runnable), установленный с помощью этого методаПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ. Если метод newThread(Runnable) возвращает null, выбрасывается RejectedExecutionException. Если ThreadFactory не задана, метод fork(Callable) создает безымянный виртуальный поток для выполнения подзадачи.

Этот метод возвращает объект SubtaskПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ в качестве дескриптора запущенной подзадачи. Если область видимости отменена, объект Subtask возвращается в состоянии UNAVAILABLEПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ без создания потока. В некоторых случаях объект Subtask используется «основной» задачей (владельцем области видимости), чтобы получить результат выполнения подзадачи (значение или исключение) после вызова метода join() для ожидания завершения всех подзадач. В других случаях область видимости создается с объектом JoinerПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ, который формирует результат для обработки основной задачей после объединения. Joiner, формирующий результат, уменьшает необходимость в учете и необходимости основной задачи сохранять ссылки на объекты Subtask для сопоставления результатов.

Чтобы обеспечить корректное использование, метод Subtask.get()ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ может вызываться только владельцем области видимости для получения результата успешно завершившейся подзадачи после ожидания завершения подзадач с помощью метода join(). Аналогично, метод Subtask.exception()ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ может вызываться только владельцем области видимости для получения исключения (или ошибки) завершившейся с ошибкой подзадачи после объединения.

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

Разработчикам Joiner:

Если область видимости была открыта с объектом JoinerПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ, его метод onFork(Subtask)ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ вызывается с только что созданным объектом Subtask до создания потока. Он вызывается, когда подзадача находится в состоянии UNAVAILABLE. Если метод выбрасывает исключение или ошибку, они передаются методом fork(Callable) дальше, и поток для выполнения подзадачи не создается. Если область видимости еще не отменена и метод onFork возвращает false, создается поток и его выполнение планируется. Если область видимости отменена или метод onFork возвращает true для отмены области видимости, метод fork(Callable) возвращает подзадачу в состоянии UNAVAILABLE.

Если подзадача выполняется и завершается (успешно или с исключением) до отмены области видимости, поток вызывает метод Joiner onComplete(Subtask)ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ, передавая подзадачу в состоянии SUCCESSПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ или FAILEDПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ. Если метод onComplete(Subtask) возвращает true, область видимости отменяется, если она еще не отменена. Если метод onComplete(Subtask) завершается с исключением или ошибкой, перед завершением потока он вызывает обработчик неперехваченных исключений.

Параметры типа:
U — тип результата
Параметры:
task — задача, возвращающая значение, для выполнения потоком
Возвращает:
подзадачу
Выбрасывает:
WrongThreadException — если текущий поток не является владельцем области видимости
IllegalStateException — если владелец уже выполнил join или область видимости закрыта
StructureViolationExceptionPREVIEW — если текущие привязки ограниченных значений не совпадают с привязками при создании области видимости
RejectedExecutionException — если фабрика потоков отклонила создание потока для выполнения подзадачи
См. также:
  • Наследование при создании потоков

fork

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

Этот метод работает точно так же, как fork(Callable), за исключением того, что его параметр — Runnable, новый поток выполняет его метод run(), а метод Subtask.get()ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ возвращает null, если подзадача завершается успешно.

Параметры типа:
U — тип результата
Параметры:
task — задача для выполнения потоком
Возвращает:
подзадачу
Выбрасывает:
WrongThreadException — если текущий поток не является владельцем области видимости
IllegalStateException — если владелец уже выполнил join или область видимости закрыта
StructureViolationExceptionPREVIEW — если текущие привязки ограниченных значений не совпадают с привязками при создании области видимости
RejectedExecutionException — если фабрика потоков отклонила создание потока для выполнения подзадачи
Начиная с версии:
25

join

R join() throws R_X, InterruptedException
Возвращает результат или выбрасывает исключение после ожидания завершения всех подзадач либо отмены области видимости.

Если область видимости была открыта методом open() или open(UnaryOperator), то join() ожидает успешного завершения всех подзадач или сбоя любой подзадачи. Он возвращает null, если все подзадачи завершились успешно. Он выбрасывает ExecutionException, если какая-либо подзадача завершилась с ошибкой; причиной будет исключение первой завершившейся с ошибкой подзадачи (причина). Если задан тайм-аутПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ и он истекает до начала ожидания или во время него, метод выбрасывает ExecutionException с CancelledByTimeoutExceptionПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ в качестве причины.

Если область видимости была открыта с объектом JoinerПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ, он вызывается после ожидания или отмены для формирования результата (значения или исключения). Сюда входит и случай тайм-аута, когда тайм-аут задан и истекает до начала ожидания в методе join() или во время него.

Этот метод может вызывать только владелец области видимости. Для получения результата, исключения или результата по тайм-ауту его можно вызвать только один раз, если только предыдущий вызов не привел к выбрасыванию InterruptedException.

Разработчикам Joiner:

После завершения всех подзадач или отмены области видимости этот метод вызывает метод Joiner result()ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ или timeout()ПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ для формирования результата (значения или исключения) метода join(). Метод result() вызывается в случае «без тайм-аута». Метод timeout() вызывается в случае тайм-аута. Если результатом для случая тайм-аута является исключение, оно выбрасывается с CancelledByTimeoutException в качестве причины.

Примечание к API:
Если результатом является исключение, трассировка стека будет содержать трассировку вызова метода join(). Его причиной обычно будет исключение, выброшенное завершившейся с ошибкой подзадачей, с трассировкой стека этой подзадачи.
Возвращает:
результат
Выбрасывает:
WrongThreadException — если текущий поток не является владельцем области видимости
IllegalStateException — если объединение уже выполнено или область видимости закрыта
R_X — если результатом является исключение
InterruptedException — если текущий поток прерван во время ожидания или этот метод вызван, когда для текущего потока установлен статус прерывания. При выбрасывании этого исключения статус прерывания текущего потока сбрасывается.
Начиная с версии:
25
См. также:
  • Прерывание потока

isCancelled

boolean isCancelled()
Возвращает true, если эта область видимости отменена или отменяется, и false в противном случае.

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

Примечание к API:
Задача с продолжительной «фазой запуска подзадач» (код в блоке try, запускающий подзадачи до вызова метода join()) может использовать этот метод, чтобы избежать выполнения работы в случаях, когда область видимости отменяется из-за завершения ранее запущенной подзадачи или истечения тайм-аута.
Возвращает:
true, если эта область видимости отменена или отменяется, и false в противном случае
Начиная с версии:
25

close

void close()
Закрывает эту область видимости.

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

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

Предполагается, что StructuredTaskScope используется структурированным образом. Если этот метод вызывается для закрытия области видимости до закрытия вложенных областей, он закрывает базовую конструкцию каждой вложенной области (в обратном порядке их создания), закрывает эту область, а затем выбрасывает StructureViolationExceptionПРЕДВАРИТЕЛЬНАЯ ВЕРСИЯ. Аналогично, если этот метод вызывается для закрытия области видимости при выполнении с привязками ограниченных значений, а область видимости была создана до привязки этих значений, то после закрытия области выбрасывается StructureViolationException. Если поток завершается, не закрыв предварительно принадлежащие ему области видимости, завершение приведет к закрытию базовой конструкции каждой открытой области. Закрытие выполняется в обратном порядке создания областей. Поэтому завершение потока может задержаться, если владелец области видимости должен дождаться завершения потоков, запущенных в этих областях.

Переопределяет:
close в интерфейсе AutoCloseable
Выбрасывает:
IllegalStateException — выбрасывается после закрытия области видимости, если владелец области видимости не пытался выполнить объединение после запуска подзадач
WrongThreadException — если текущий поток не является владельцем области видимости
StructureViolationExceptionPREVIEW — если обнаружено нарушение структуры

Сообщить об ошибке или предложить улучшение
Для получения дополнительных справочных материалов по API и документации для разработчиков см. Документацию Java SE, которая содержит более подробные описания для разработчиков, концептуальные обзоры, определения терминов, обходные решения и примеры работающего кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или её аффилированных лиц в США и других странах.
Авторское право © 1993, 2026, Oracle и/или её аффилированные лица, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
Все права защищены. Использование регулируется условиями лицензии и политикой распространения документации.

© 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.

Spec-Zone.ru

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