Scoped Values — неизменяемый контекст вместо ThreadLocal

Тема дорожной карты · Java

Scoped values — механизм передачи неизменяемого контекста «сверху вниз» по цепочке вызовов без явных параметров в каждой сигнатуре и без ThreadLocal. После нескольких раундов инкубации и preview API финализирован в Java 25 (JEP 506) — это стабильная функциональность, никакие флаги не нужны. Типовой сценарий: в начале обработки запроса положить в контекст данные аутентифицированного пользователя, trace-id или транзакцию, а читать их глубоко в стеке — в сервисах, репозиториях, логировании.

Как это работает

private static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();

void serve(Request request) {
    User user = authenticate(request);
    ScopedValue.where(CURRENT_USER, user)    // связывание
               .run(() -> handle(request));  // видно всей цепочке вызовов
}

void audit(String action) {
    log.info(CURRENT_USER.get().name() + ": " + action);
}

Связывание существует только на время выполнения run()/call() и снимается автоматически, даже если код завершился исключением. Значение неизменяемо: метода set() нет вовсе, «поменять» его можно только перевязав во вложенном where (rebinding), и после выхода из вложенного блока снова видна прежняя привязка. Чтение вне области связывания бросает NoSuchElementException; для необязательного контекста есть isBound() и orElse(). Главное отличие от InheritableThreadLocal: подзадачи, порождённые через fork() в структурированном параллелизме, видят scoped values родителя без копирования — наследуется ссылка на неизменяемые данные. Поэтому механизм остаётся практически бесплатным даже при миллионах виртуальных потоков, где копирующее наследование стало бы заметной статьёй расходов памяти.

У ThreadLocal три хронические проблемы: неограниченная мутабельность (записать значение может любой код в любой момент), утечки в пулах, где поток живёт дольше задачи и продолжает хранить чужие данные, и дорогое наследование с копированием таблицы значений в каждый дочерний поток. Scoped values закрывают все три разом — неизменяемостью и жёсткой привязкой значения к области выполнения.

Когда применять

Типичные ошибки

Связанные понятия

Полезные ресурсы

Проверить знания (2)

Загрузка вопросов…