Spec-Zone.ru › OpenJDK 21

Класс ScopedValue<T>

java.lang.Object
java.lang.ScopedValue<T>
Type Parameters:
T - тип значения
public final class ScopedValue<T> extends Object
ScopedValue — это предварительный API платформы Java.
Программы могут использовать ScopedValue только при включенных предварительных функциях.
Предварительные функции могут быть удалены в будущих выпусках или доработаны до постоянных функций платформы Java.
Значение, которое можно безопасно и эффективно передавать методам без использования параметров метода.

В языке программирования Java данные обычно передаются методу посредством параметра метода. Данные могут потребоваться передать через последовательность многих методов, чтобы добраться до метода, который использует данные. Каждый метод в цепочке вызовов должен объявить параметр, и каждый метод имеет доступ к данным. ScopedValue предоставляет способ передачи данных удаленному методу (обычно обработчику) без использования параметров метода. По сути, ScopedValue является неявным параметром метода. Это «как будто» каждый метод в последовательности вызовов имеет дополнительный параметр. Ни один из методов не объявляет параметр, и только методы, которые имеют доступ к объекту ScopedValue, могут получить доступ к его значению (данным). ScopedValue позволяет безопасно передавать данные от вызывающего метода к вызываемому методу через последовательность промежуточных методов, которые не объявляют параметр для данных и не имеют доступа к данным.

API ScopedValue работает путём выполнения метода с объектом ScopedValue, связанным с некоторым значением на ограниченный период выполнения метода. Метод может вызвать другой метод, который, в свою очередь, может вызвать другой. Развертывание выполнения методов определяет динамическую область видимости. Код в этих методах с доступом к объекту ScopedValue может прочитать его значение. Объект ScopedValue возвращается к состоянию несвязанности, когда исходный метод завершается нормально или с исключением. API ScopedValue поддерживает выполнение метода Runnable.run, Callable.call или Supplier.get с объектом ScopedValue, связанным со значением.

Рассмотрим следующий пример со скопированным значением «NAME», связанным со значением «duke» для выполнения метода run. Метод run, в свою очередь, вызывает doSomething.

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

    ScopedValue.runWhere(NAME, "duke", () -> doSomething());
Код, выполняемый напрямую или косвенно doSomething, с доступом к полю NAME, может вызвать NAME.get() для чтения значения «duke». NAME связан во время выполнения метода run. Он возвращается к состоянию несвязанности, когда метод run завершается.

Пример с использованием runWhere вызывает метод, который не возвращает результат. Методы callWhere и getWhere могут использоваться для вызова метода, возвращающего результат. Кроме того, ScopedValue определяет метод where(ScopedValue, Object) для случаев, когда несколько сопоставлений (ScopedValue со значением) накапливаются до вызова метода со всеми ScopedValue связанными со своим значением.

Связывания по потокам

Связывание ScopedValue со значением происходит в рамках каждого потока. Вызов xxxWhere выполняет метод с ScopedValue, связанным со значением для текущего потока. Метод get возвращает связанное значение для текущего потока.

В примере, если код, выполняемый одним потоком, вызывает это:

    ScopedValue.runWhere(NAME, "duke1", () -> doSomething());
и код, выполняемый другим потоком, вызывает:
    ScopedValue.runWhere(NAME, "duke2", () -> doSomething());
то код в doSomething (или любой метод, который он вызывает), вызывающий NAME.get() , прочитает значение «duke1» или «duke2», в зависимости от того, какой поток выполняет код.

Scoped values как возможности

Объект ScopedValue следует рассматривать как возможность или ключ для доступа к его значению, когда ScopedValue связан. Безопасное использование зависит от контроля доступа (см. Спецификацию виртуальной машины Java, Раздел 5.4.4) и заботы о том, чтобы не делиться объектом ScopedValue. Во многих случаях ScopedValue будет объявлен в поле final и static для доступа только коду в одном классе (или вложенности).

Переназначение

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

В приведенном выше примере, предположим, что код, выполняемый doSomething, связывает NAME с новым значением с помощью:

    ScopedValue.runWhere(NAME, "duchess", () -> doMore());
Код, выполняемый напрямую или косвенно doMore(), вызывающий NAME.get(), прочитает значение «duchess». По завершении doMore() значение NAME возвращается к «duke».

Наследование

ScopedValue поддерживает совместное использование между потоками. Это совместное использование ограничено структурированными случаями, когда дочерние потоки запускаются и завершаются в рамках ограниченного периода выполнения родительским потоком. При использовании StructuredTaskScopeПРЕДПРОСМОТР, связывания скопированных значений захватываются при создании StructuredTaskScope и наследуются всеми потоками, запущенными в этой области задач с помощью метода forkПРЕДПРОСМОТР.

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

В следующем примере ScopedValue NAME связан со значением «duke» для выполнения действия runnable. Код в методе run создает StructuredTaskScope , который разветвляет три задачи. Код, выполняемый непосредственно или косвенно этими потоками, выполняющими childTask1(), childTask2(), и childTask3() , вызывающий NAME.get() , прочитает значение «duke».

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

    ScopedValue.runWhere(NAME, "duke", () -> {
        try (var scope = new StructuredTaskScope<String>()) {

            scope.fork(() -> childTask1());
            scope.fork(() -> childTask2());
            scope.fork(() -> childTask3());

            ...
         }
    });

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

API Note:
A ScopedValue следует предпочитать ThreadLocal в тех случаях, когда целью является «однонаправленная передача» данных без использования параметров метода. Хотя ThreadLocal может использоваться для передачи данных методу без использования параметров метода, это приводит к ряду проблем:
  1. ThreadLocal не предотвращает код в вызываемом методе на расстоянии от изменения нового значения.
  2. У ThreadLocal неограниченный срок службы, и поэтому значение сохраняется после завершения метода, пока явно не будет удалено.
  3. Наследование является дорогостоящим - карта потоковых локалей и значений должна быть скопирована при создании каждого дочернего потока.
Implementation Note:
Значения области действия предназначены для использования в небольшом количестве. get() изначально выполняет поиск по вложенным областям действия, чтобы найти самое внутреннее связывание значения области действия. Затем он кэширует результат поиска в небольшом кэше потоковых локалей. Последующие вызовы get() для этого значения области действия практически всегда будут очень быстрыми. Однако, если программа использует много значений области действия циклически, коэффициент попадания в кэш будет низким, и производительность будет плохой. Данный дизайн позволяет быстрому наследованию значений области действия в потоках StructuredTaskScopeПРЕВЬЮ: по сути, не больше чем копирование указателя, и освобождение связи значения области действия также требует не больше, чем обновления указателя.

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

Для этой версии реализация предоставляет некоторые системные свойства для настройки производительности значений области действия.

Системное свойство java.lang.ScopedValue.cacheSize управляет размером кэша значений области действия (на поток). Этот кэш имеет решающее значение для производительности значений области действия. Если он слишком мал, среда выполнения будет неоднократно сканировать для каждого get(). Если он слишком велик, память будет излишне потребляться. По умолчанию размер кэша значений области действия составляет 16 элементов. Его можно изменять от 2 до 16 элементов. ScopedValue.cacheSize должен быть целой степенью двойки.

Например, можно использовать -Djava.lang.ScopedValue.cacheSize=8.

Другое системное свойство - jdk.preserveScopedValueCache. Это свойство определяет, сохраняется ли кэш значений области действия на поток при блокировке виртуального потока. По умолчанию это свойство установлено в значение true, что означает, что каждый виртуальный поток сохраняет свой кэш значений области действия при блокировке. Как и ScopedValue.cacheSize, это компромисс между местом и скоростью: в ситуациях, когда многие виртуальные потоки заблокированы большую часть времени, установка этого свойства в false может привести к экономии памяти, но кэш значений области действия каждого виртуального потока придется восстанавливать после операции блокировки.

Since:
21

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

Модификатор и тип Класс Описание
static final class  ScopedValue.CarrierPREVIEW
Превью.
Сопоставление значений области действия, как ключей, со значениями.

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

Модификатор и тип Метод Описание
static <T, R> R callWhere(ScopedValuePREVIEW<T> key, T value, Callable<? extends R> op)
Вызывает операцию возвращающую значение с ScopedValue, связанной со значением в текущем потоке.
T get()
Возвращает значение области действия, если оно связано в текущем потоке.
static <T, R> R getWhere(ScopedValuePREVIEW<T> key, T value, Supplier<? extends R> op)
Вызывает поставщика результатов с ScopedValue, связанным со значением в текущем потоке.
boolean isBound()
Возвращает true, если это значение области действия связано в текущем потоке.
static <T> ScopedValuePREVIEW<T> newInstance()
Создаёт значение области действия, которое изначально не связано для всех потоков.
T orElse(T other)
Возвращает значение этого значения области действия, если оно связано в текущем потоке, в противном случае возвращает other.
<X extends Throwable>
T
orElseThrow(Supplier<? extends X> exceptionSupplier)
Возвращает значение этого значения области действия, если оно связано в текущем потоке, в противном случае выбрасывает исключение, сгенерированное функцией, предоставляющей исключение.
static <T> void runWhere(ScopedValuePREVIEW<T> key, T value, Runnable op)
Выполняет операцию с ScopedValue, связанным со значением в текущем потоке.
static <T> ScopedValue.CarrierPREVIEW where(ScopedValuePREVIEW<T> key, T value)
Создаёт новое Carrier с одним отображением ScopedValue ключа на значение.

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

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

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

where

public static <T> ScopedValue.CarrierPREVIEW where(ScopedValuePREVIEW<T> key, T value)
Создаёт новый Carrier с единственным сопоставлением ключа ScopedValue со значением. Carrier можно использовать для накопления сопоставлений, чтобы операция могла быть выполнена со всеми связанными значениями в сопоставлении. Следующий пример выполняет операцию со связанным (или пересвязанным) k1 со значением v1, и k2 со значением v2.
    ScopedValue.where(k1, v1).where(k2, v2).run(() -> ... );
Параметры типа:
T - тип значения
Параметры:
key - ключ ScopedValue
value - значение, может быть null
Возвращает:
новый Carrier с единственным сопоставлением

callWhere

public static <T, R> R callWhere(ScopedValuePREVIEW<T> key, T value, Callable<? extends R> op) throws Exception
Вызывает операцию, возвращающую значение, со связанным ScopedValue со значением в текущей нити. Когда операция завершается (нормально или с исключением), ScopedValue вернётся к развязанному состоянию или к предыдущему связанному значению в текущей нити. Если op завершается с исключением, то оно передаётся этим методом.

Значения со scope предназначены для использования в структурированном виде. Если код, вызванный напрямую или косвенно операцией, создаёт StructuredTaskScopeПРОСМОТР, но не закрываетПРОСМОТР его, то это обнаруживается как нарушение структуры при завершении операции (нормально или с исключением). В этом случае базовая конструкция StructuredTaskScope закрывается и выбрасывается StructureViolationExceptionПРОСМОТР.

Примечание по реализации:
Этот метод реализован для соответствия:
    ScopedValue.where(key, value).call(op);
Параметры типа:
T - тип значения
R - тип результата
Параметры:
key - ключ ScopedValue
value - значение, может быть null
op - операция для вызова
Возвращает:
результат
Исключение:
StructureViolationExceptionPREVIEW - если обнаружено нарушение структуры
Exception - если операция завершается с исключением

getWhere

public static <T, R> R getWhere(ScopedValuePREVIEW<T> key, T value, Supplier<? extends R> op)
Вызывает поставщика результатов со связанным ScopedValue со значением в текущей нити. Когда операция завершается (нормально или с исключением), ScopedValue вернётся к развязанному состоянию или к предыдущему связанному значению в текущей нити. Если op завершается с исключением, то оно передаётся этим методом.

Значения со scope предназначены для использования в структурированном виде. Если код, вызванный напрямую или косвенно операцией, создаёт StructuredTaskScopeПРОСМОТР, но не закрываетПРОСМОТР его, то это обнаруживается как нарушение структуры при завершении операции (нормально или с исключением). В этом случае базовая конструкция StructuredTaskScope закрывается и выбрасывается StructureViolationExceptionПРОСМОТР.

Примечание по реализации:
Этот метод реализован для соответствия:
    ScopedValue.where(key, value).get(op);
Параметры типа:
T - тип значения
R - тип результата
Параметры:
key - ключ ScopedValue
value - значение, может быть null
op - операция для вызова
Возвращает:
результат
Исключение:
StructureViolationExceptionPREVIEW - если обнаружено нарушение структуры

runWhere

public static <T> void runWhere(ScopedValuePREVIEW<T> key, T value, Runnable op)
Выполняет операцию со связанным ScopedValue со значением в текущей нити. Когда операция завершается (нормально или с исключением), ScopedValue вернётся к развязанному состоянию или к предыдущему связанному значению в текущей нити. Если op завершается с исключением, то оно передаётся этим методом.

Значения со scope предназначены для использования в структурированном виде. Если код, вызванный напрямую или косвенно операцией, создаёт StructuredTaskScopeПРОСМОТР, но не закрываетПРОСМОТР его, то это обнаруживается как нарушение структуры при завершении операции (нормально или с исключением). В этом случае базовая конструкция StructuredTaskScope закрывается и выбрасывается StructureViolationExceptionПРОСМОТР.

Примечание по реализации:
Этот метод реализован для соответствия:
    ScopedValue.where(key, value).run(op);
Параметры типа:
T - тип значения
Параметры:
key - ключ ScopedValue
value - значение, может быть null
op - операция для вызова
Исключение:
StructureViolationExceptionPREVIEW - если обнаружено нарушение структуры

newInstance

public static <T> ScopedValuePREVIEW<T> newInstance()
Создаёт значение со scope, которое изначально развязано для всех нитей.
Параметры типа:
T - тип значения
Возвращает:
новый ScopedValue

get

public T get()
Возвращает значение значения со scope, если оно связано в текущей нити.
Возвращает:
значение значения со scope, если оно связано в текущей нити
Исключение:
NoSuchElementException - если значение со scope не связано

isBound

public boolean isBound()
Возвращает true, если это значение со scope связано в текущей нити.
Возвращает:
true если это значение со scope связано в текущей нити

orElse

public T orElse(T other)
Возвращает значение этого значения со scope, если оно связано в текущей нити, в противном случае возвращает other.
Параметры:
other - значение для возврата, если оно не связано, может быть null
Возвращает:
значение значения со scope, если оно связано, в противном случае other

orElseThrow

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
Возвращает значение этого значения со scope, если оно связано в текущей нити, в противном случае выбрасывает исключение, сгенерированное функцией, возвращающей исключение.
Параметры типа:
X - тип исключения, которое может быть выброшено
Параметры:
exceptionSupplier - функция, которая возвращает исключение для выброса
Возвращает:
значение значения со scope, если оно связано в текущей нити
Исключение:
X - если значение со scope не связано в текущей нити

© 1993, 2023, 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://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ScopedValue.html

Spec-Zone.ru

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