Modern Java is improving two different problems: passing immutable context through a bounded call tree and treating related subtasks as one unit of work. The APIs have different release status. Mixing them into a Java 21 baseline would hide a major production compatibility decision.
Quick answer
Scoped Values are a final, permanent API in Java 25 for one-way, bounded sharing of immutable context. They avoid much of the mutable, unbounded lifetime associated with ThreadLocal. Structured Concurrency remains a preview API: JEP 525 delivers its sixth preview in JDK 26. It groups forked subtasks under a lexical scope so joining, failure, cancellation, and observability can follow the task tree. Preview APIs can change and are not a universal production guarantee.
Learning objectives
- Choose Java 25 Scoped Values for bounded immutable context without treating them as authorization or automatic cross-process propagation.
- Evaluate JDK 26 Structured Concurrency as a preview task-lifetime model with explicit build, runtime, failure, and migration constraints.
Prerequisites
Read Java Virtual Threads for Backend Services and Java Interruption, Cancellation, and Deadlines. This version-isolated lesson is part of the Java Concurrency course and topic cluster.
Java 25: Scoped Values are final
Version boundary: Java 25, final API (JEP 506). This is not Java 21 baseline code.
A ScopedValue<T> binding is available only while the binding operation runs and is restored automatically when the dynamic scope exits. The value should be immutable or treated as immutable. That makes data flow easier to reason about than a mutable ThreadLocal that any method can set and forget to clear.
// Java 25 final API. Compile with: javac --release 25 ScopedRequest.java
import java.lang.ScopedValue;
final class ScopedRequest {
static final ScopedValue<String> TRACE_ID = ScopedValue.newInstance();
static void handle(String traceId) {
ScopedValue.where(TRACE_ID, traceId).run(() -> audit(TRACE_ID.get()));
}
static void audit(String traceId) {
System.out.println(traceId);
}
}
Scoped Values do not authenticate the value, grant authorization, propagate it over HTTP, or make a mutable object safe. Pass trusted business identity explicitly. Use observability context according to the tracing library’s supported propagation contract.
JDK 26: Structured Concurrency is sixth preview
Version boundary: JDK 26 Preview 6 (JEP 525). This code requires preview at compile time and runtime and must not be mixed into the Java 21 baseline.
// JDK 26 sixth preview.
// Compile: javac --release 26 --enable-preview OrderSummary.java
// Run: java --enable-preview OrderSummary
import java.util.concurrent.StructuredTaskScope;
final class OrderSummary {
static String load() throws Exception {
try (var scope = StructuredTaskScope.open()) {
var order = scope.fork(() -> "order");
var stock = scope.fork(() -> "stock");
scope.join();
return order.get() + ":" + stock.get();
}
}
public static void main(String[] args) throws Exception {
System.out.println(load());
}
}
The exact JDK 26 API and policies must be verified against the selected build; preview signatures can change. A scope makes child lifetime visible, but the chosen joiner/policy determines how failures and success are handled. Cancellation still relies on task cooperation and cannot roll back already committed database or external effects.
ThreadLocal versus ScopedValue
ThreadLocal provides mutable per-thread storage whose lifetime can accidentally extend across pooled task reuse. Correct code must remove values. Virtual threads reduce reuse concerns but can multiply per-thread memory. ScopedValue offers bounded, one-way rebinding that follows a lexical operation, which better communicates immutable context. Neither should become a hidden bag of business inputs.
Spring SecurityContext, MDC, transactions, and tracing have framework-specific ownership. Do not assume converting one field to ScopedValue propagates all of them or changes their trust boundary.
Failure scenario: orphaned subtasks
A request launches two CompletableFuture calls and returns after the first failure. The second call continues, consumes a connection, and writes a side effect after the caller times out. A structured scope can make sibling lifetime and join policy explicit, but only if the dependency honors interruption and the side effect has its own idempotency and reconciliation contract. Preview structure improves ownership; it does not manufacture rollback.
Common misconceptions
- ScopedValue is not available as a final API on Java 21; the final API is Java 25.
- Structured Concurrency is still preview in JDK 26 and can continue changing.
- Lexical task structure does not guarantee external exactly-once effects.
- Cancellation is cooperative even when a scope requests it for sibling tasks.
- Context propagation is not authorization and does not automatically cross network boundaries.
Production validation
Pin the exact JDK and compiler flags in CI. For preview evaluation, compile with --release 26 --enable-preview and run with --enable-preview; reject artifacts missing either boundary. Test primary failure, sibling failure, timeout, caller interruption, partial external completion, and scope close. Inspect task trees and JFR evidence, verify context is unavailable after scope exit, and scan for mutable or sensitive values. Maintain a migration plan for the next JDK because preview API changes are allowed.
Continue to Production Java Concurrency Troubleshooting and use the Java Concurrency Budget Lab for a stable Java-version-neutral capacity model.
FAQ
Can Java 21 applications use the final ScopedValue API?
No. The final API described by JEP 506 is in Java 25. Keep Java 25 code in a separately versioned source set or service.
Is Structured Concurrency production-stable in JDK 26?
No. JEP 525 is the sixth preview. Preview use requires explicit flags and an accepted upgrade/migration policy.
Does a structured scope cancel an HTTP payment safely?
It can request cancellation of the task. The payment outcome still needs the provider’s deadline, idempotency, status, and reconciliation semantics.
Related reading
Use the Java Concurrency learning path, topic cluster, and CompletableFuture guide to compare unstructured composition with scoped task ownership.
Official sources
- JEP 506: Scoped Values — accessed August 18, 2026.
- JEP 525: Structured Concurrency — accessed August 18, 2026.
- Java SE 26 StructuredTaskScope — accessed August 18, 2026.