Класс StructuredTaskScope<T>
- Параметры типа:
T- тип результата задач, выполняемых в области задач
- Все реализованные интерфейсы:
AutoCloseable
- Непосредственные известные подклассы:
-
StructuredTaskScope.ShutdownOnFailurePREVIEW,StructuredTaskScope.ShutdownOnSuccessPREVIEW
public class StructuredTaskScope<T> extends Object implements AutoCloseable
StructuredTaskScope — это предварительный API платформы Java. 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 для реализации политики для общих случаев: -
ShutdownOnSuccessPREVIEW захватывает результат первой подзадачи, завершившейся успешно. После захвата он останавливает область задачи, прерывает незавершенные потоки и будит владельца. Этот класс предназначен для случаев, когда результат любой подзадачи подходит ("вызвать любую") и нет необходимости ожидать результатов других незавершенных подзадач. Он определяет методы для получения первого результата или выброса исключения, если все подзадачи завершатся неудачно. -
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));
...
}
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 |
Создаёт область задач с заданным именем и фабрикой потоков. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
void |
close() |
Закрывает эту область задач. |
protected final void |
ensureOwnerAndJoined() |
Убеждается, что текущий поток является владельцем этой области задач и что он присоединился (с помощью join() или joinUntil(Instant)) после создания подзадач. |
<U extends T> |
fork |
Запускает новый поток в этой области задач для выполнения задачи, возвращающей значение, тем самым создавая подзадачу этой области задач. |
protected void |
handleComplete |
Вызывается подзадачей при её успешном завершении или возникновении ошибки в этой области задач. |
final boolean |
isShutdown() |
Возвращает true, если эта область задач закрыта, иначе false. |
StructuredTaskScopePREVIEW |
join() |
Ожидает завершения всех подзадач, запущенных в этой области задач, или закрытия области задач. |
StructuredTaskScopePREVIEW |
joinUntil |
Ожидает завершения всех подзадач, запущенных в этой области задач, или закрытия области задач до указанного срока. |
void |
shutdown() |
Закрывает эту область задач без её закрытия. |
Подробное описание конструкторов
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
public final boolean isShutdown()
- Returns:
- true, если этот контекст задачи остановлен, иначе false
- See Also:
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
StructuredTaskScopeтолько при включенных предварительных функциях.