tgoop.com/javaproglib/6382
Last Update:
Разберем новую фичу Java 21 — Scoped Values, которая пришла на замену (а точнее, в дополнение) к старому доброму ThreadLocal. Если вы когда-либо мучились с ThreadLocal в многопоточных приложениях, этот пост для вас.
ThreadLocal — это механизм для хранения данных, привязанных к потоку. Но у него есть недостатки:
— Данные остаются в потоке, даже когда уже не нужны (утечки памяти).
— Передавать данные в дочерние потоки неудобно.
— Нужно очистить данные вручную.
Scoped Values решают эти проблемы без магии и костылей.
Scoped Values (ScopedValue<T>) создаются только один раз и не изменяются после инициализации. Они передаются вглубь стека вызовов через метод ScopedValue.where(), а не через хранение в потоке, как ThreadLocal.
▪️ Пример кода с потоками
Допустим, есть обработчик запросов, который передает идентификатор пользователя.
— С ThreadLocal код выглядел бы так:
public class ThreadLocalExample {
private static final ThreadLocal<String> USER = new ThreadLocal<>();
public static void main(String[] args) {
USER.set("Alice");
new Thread(ThreadLocalExample::process).start();
}
private static void process() {
System.out.println("User: " + USER.get()); // null: поток не видит значение
}
}
ThreadLocal привязан к потоку, а не к области выполнения. Значение не наследуется
Теперь переделаем на Scoped Values:
public class ScopedValueExample {
private static final ScopedValue<String> USER = ScopedValue.newInstance();
public static void main(String[] args) {
ScopedValue.where(USER, "Alice").run(() -> {
new Thread(ScopedValueExample::process).start();
});
}
private static void process() {
System.out.println("User: " + USER.get()); // ✅ Видит "Alice"
}
}
Scoped Values автоматически передают значение в новые потоки.
🎯 Где использовать Scoped Values
1. Контекст запроса (Request Context)
В веб-приложениях часто нужно передавать ID запроса или текущего пользователя через слои сервиса.
2. Логирование (Tracing & Logging)
Можно автоматически передавать traceId в логи.
3. Конфигурация временных параметров
Можно временно менять настройки для фрагмента кода.
— ScopedValue быстрее и безопаснее, так как нет необходимости очищать значения вручную.
— Отлично подходит для работы с виртуальными потоками.
— Ограничение: они неизменяемые (Immutable).