middle
Scoped Values — замена ThreadLocal?
Scoped Values — механизм для передачи иммутабельных данных через стек вызовов без явной передачи параметров. Альтернатива ThreadLocal, разработанная специально для Virtual Threads — не создаёт копию на каждый поток и автоматически ограничивает время жизни.
ThreadLocal vs ScopedValue
| Критерий | ThreadLocal | ScopedValue |
|---|---|---|
| Мутабельность | Мутабельный (set()) |
Immutable (только where().run()) |
| Время жизни | Пока не вызван remove() |
Автоматически — ограничен run()/call() |
| Наследование | InheritableThreadLocal (копия) |
Автоматическое наследование в child-scope |
| Память | Копия на каждый поток | Разделяемая ссылка |
| Virtual Threads | Проблема (миллион копий = OOM) | Оптимально |
Пример
// ThreadLocal — проблемы с Virtual Threads:
private static final ThreadLocal<User> CURRENT_USER = new ThreadLocal<>();
CURRENT_USER.set(user);
// ... где-то в стеке вызовов:
User u = CURRENT_USER.get();
CURRENT_USER.remove(); // легко забыть!
// ScopedValue — решение:
private static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();
ScopedValue.where(CURRENT_USER, authenticatedUser)
.run(() -> {
// CURRENT_USER доступен во всём этом scope
processRequest();
});
// В вызываемом коде:
void processRequest() {
User user = CURRENT_USER.get(); // доступно
// user автоматически недоступен после выхода из run()
}
Частые ошибки
- Вызвать
get()внеrun()—NoSuchElementException; ScopedValue доступен только в scope - Использовать ThreadLocal с миллионами Virtual Threads — OOM; мигрируйте на ScopedValue
- ScopedValue для мутабельного состояния — ScopedValue immutable; для мутабельного состояния нужен другой подход
Как используется в 2026
- ScopedValue финализирован в Java 25
- Используется для propagation authentication context, trace ID, request metadata
- Spring Security и Micrometer начинают поддержку ScopedValue для Virtual Threads
На собеседовании: объясните три проблемы ThreadLocal с Virtual Threads (мутабельность, утечки, память) и как ScopedValue решает каждую. Частая ошибка — не знать про автоматическое наследование в child-scope при Structured Concurrency.