Working with Scoped Values JAVA 21+ PREVIEW
1. Understanding Scoped Values
| Aspect | Detail |
|---|---|
| Purpose | Pass immutable data implicitly to inner methods |
| Replaces | ThreadLocal in many cases |
| Lifetime | Bounded by enclosing scope (lexical) |
2. Creating Scoped Values
| Form | Detail |
|---|---|
| Declaration | static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance(); |
| Usually static final | Like a typed key |
3. Binding Values
Example: Binding
ScopedValue.where(CURRENT_USER, user)
.where(REQUEST_ID, id)
.run(() -> processRequest());
| Method | Detail |
|---|---|
where(sv, val) | Bind value |
run(runnable) | Execute body |
call(callable) | Execute and return |
4. Reading Scoped Values
| Method | Detail |
|---|---|
sv.get() | Returns bound value or throws |
sv.isBound() | Check before reading |
sv.orElse(default) | Default if unbound |
5. Scoping Rules
| Rule | Detail |
|---|---|
| Immutable | Cannot reassign within scope |
| Lexical | Available only inside run/call |
| Inheritance | Forked vthreads in same scope inherit |
6. Comparing with ThreadLocal
| Aspect | ScopedValue | ThreadLocal |
|---|---|---|
| Mutability | Immutable | Mutable |
| Lifetime | Bounded | Until explicit remove |
| Memory | Per-scope, light | Per-thread, heavy with vthreads |
| Inheritance | Automatic via structured concurrency | Via InheritableThreadLocal |
7. Using with Virtual Threads
| Aspect | Detail |
|---|---|
| Memory efficient | Critical with millions of vthreads |
| No leaks | Auto cleared after scope ends |
8. Inheritance in Structured Concurrency
| Aspect | Detail |
|---|---|
| Auto-inherited | Subtasks forked in scope see all bindings |
| Override | Re-bind in child scope |
9. Best Practices
| Practice | Reason |
|---|---|
| Use for context propagation | Tracing IDs, security principals, locales |
| Don't store mutable objects | Defeats purpose |
| Prefer over ThreadLocal | Especially with virtual threads |
10. Migration Strategies
| Step | Detail |
|---|---|
| Identify ThreadLocals | Used for request-scoped data |
| Convert | Replace with ScopedValue |
| Wrap entry points | Bind at request boundary |
| Audit get sites | Replace with sv.get() |