Scoped values
Share data across call stacks safely without ThreadLocal pitfalls.
Code Comparison
✕ Java 8
static final ThreadLocal<User> CURRENT =
new ThreadLocal<>();
void handle(Request req) {
CURRENT.set(authenticate(req));
try { process(); }
finally { CURRENT.remove(); }
}
✓ Java 25
static final ScopedValue<User> CURRENT =
ScopedValue.newInstance();
void handle(Request req) {
ScopedValue.where(CURRENT,
authenticate(req)
).run(this::process);
}
Why the modern way wins
Immutable
Callees can read but never modify the scoped value.
Auto cleanup
No manual remove() — value is scoped to the block.
Virtual-thread safe
Works efficiently with millions of virtual threads.
Old Approach
ThreadLocal
Modern Approach
ScopedValue
Since JDK
25
Difficulty
advanced
JDK Support
Scoped values
Available
Finalized in JDK 25 LTS (JEP 506, Sept 2025).
How it works
ScopedValue provides immutable, inheritable, scope-limited context. Unlike ThreadLocal, scoped values are automatically cleaned up, work with virtual threads, and can't be mutated by callees.