Spec-Zone.ru › OpenJDK 24

Класс ScopedValue

java.lang.Object
java.lang.ScopedValue
Параметры типа:
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 или ScopedValue.CallableOpПРЕДПРОСМОТР с ScopedValue, привязанным к значению.

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

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

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

В примере с использованием run вызывается метод, не возвращающий результат. Метод callПРЕДПРОСМОТР может использоваться для вызова метода, возвращающего результат. ScopedValue определяет метод where(ScopedValue, Object) для случаев, когда несколько сопоставлений (ScopedValue со значением) накапливаются до вызова метода со всеми ScopedValue, привязанными к своим значениям.

Привязки выполняются в рамках потока

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

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

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

Скопированные значения как возможности

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

Перепривязка

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

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

    ScopedValue.where(NAME, "duchess").run(() -> 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.where(NAME, "duke").run(() -> {
        try (var scope = new StructuredTaskScope<String>()) {

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

             scope.join();

             ..
         }
    });

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

Примечание API:
Для случаев, когда цель заключается в «односторонней передаче» данных без использования параметров метода, следует предпочесть ThreadLocal вместо ScopedValue. Хотя ThreadLocal можно использовать для передачи данных методу без параметров метода, это приводит к ряду проблем:
  1. Устанавливать новое значение не блокируется кодом в удалённом вызывающем объекте.
  2. ThreadLocal имеет неограниченный срок жизни и, таким образом, продолжает иметь значение после завершения метода, если его не удалить явно с помощью удаления.
  3. Наследование с использованием наследования является ресурсоёмким – при создании каждого дочернего потока необходимо копировать карту нитей-локалей к значениям.
Примечание реализации:
Значения области действия предназначены для использования в небольшом количестве. 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 может привести к полезной экономии памяти, но кэш значений области действия каждой виртуальной нити должен будет быть восстановлен после операции блокировки.

С тех пор как:
21

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

Модификатор и тип Класс Описание
static interface  ScopedValue.CallableOpPREVIEW<T, X extends Throwable>
Просмотр.
Операция, возвращающая результат и, возможно, выбрасывающая исключение.
static final class  ScopedValue.CarrierPREVIEW
Просмотр.
Сопоставление значений области действия, как ключи, со значениями.

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

Модификатор и тип Метод Описание
T get()
Возвращает значение значения области действия, если оно привязано в текущей нити.
boolean isBound()
Возвращает true, если это значение области действия привязано в текущей нити.
static <T> ScopedValuePREVIEW<T> newInstance()
Создаёт значение области действия, которое изначально не привязано для всех нитей.
T orElse(T other)
Возвращает значение этого значения области действия, если оно привязано в текущей нити, в противном случае возвращает other.
<X extends Throwable>
T
orElseThrow(Supplier<? extends X> exceptionSupplier)
Возвращает значение этого значения области действия, если оно привязано в текущей нити, в противном случае выбрасывает исключение, созданное функцией предоставления исключений.
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 с одиночным отображением

newInstance

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

get

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

isBound

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

orElse

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

orElseThrow

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

© 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/lang/ScopedValue.html

Spec-Zone.ru

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