ScopedValue
Значение, доступное коду только на время вызова — например, текущий пользователь запроса. Замена ThreadLocal.
Доступно с: Java 25
Синтаксис
public final class ScopedValue<T>Примеры
Значение привязывается через where(...).run(...) и читается через get() в любом вызванном методе:
static final ScopedValue<String> USER = ScopedValue.newInstance();
void handle() {
IO.println("Handling request for " + USER.get());
}
void main() {
ScopedValue.where(USER, "Anna").run(this::handle);
IO.println(USER.isBound());
}Результат:
Handling request for Anna
falsecall() возвращает результат, а вложенная привязка временно заменяет значение:
static final ScopedValue<String> USER = ScopedValue.newInstance();
String greet() {
return "Hello, " + USER.orElse("guest");
}
void main() {
IO.println(greet());
IO.println(ScopedValue.where(USER, "Oleg").call(this::greet));
ScopedValue.where(USER, "Anna").run(() -> {
IO.println(greet());
ScopedValue.where(USER, "Mia").run(() -> IO.println(greet()));
IO.println(greet());
});
}Результат:
Hello, guest
Hello, Oleg
Hello, Anna
Hello, Mia
Hello, AnnaЧтение вне привязки:
static final ScopedValue<String> USER = ScopedValue.newInstance();
void main() {
USER.get();
}Результат:
Exception in thread "main" java.util.NoSuchElementException: ScopedValue not boundПримечания
В отличие от ThreadLocal, значение нельзя изменить — только привязать заново на время вложенного вызова, а после выхода из run() оно исчезает само. Так данные не «утекают» между запросами и не требуют ручной очистки. Обычно объект объявляют как static final поле. Значение видно в дочерних потоках StructuredTaskScope (структурный параллелизм, в Java 25 — превью). Финальная версия API — Java 25.
См. также
- Thread.currentThread() — Возвращает поток, который выполняет текущий код.
- Thread.ofVirtual() — Создаёт виртуальный поток — лёгкий поток, которых можно запустить миллионы.
- Executors.newVirtualThreadPerTaskExecutor() — Создаёт сервис, который запускает каждую задачу в отдельном виртуальном потоке.
- Runnable — Задача без аргументов и без результата.
В учебнике
- Ограниченные значения (ScopedValue) — ScopedValue в Java 25 — как передать данные вглубь вызовов без параметров, ScopedValue.newInstance, where(...).run(...), get, вложенная привязка и почему они заменяют ThreadLocal в виртуальных потоках.