ScopedValue: The ThreadLocal Replacement Java 25 Finalized

In the ThreadLocal leak post, ScopedValue was the third fix — two paragraphs and a filter snippet. This is the full treatment, because JDK 25 changed its status: after an incubator round in JDK 20 and previews in JDK 21–24, JEP 506 made java.lang.ScopedValue final in JDK 25. No preview flag. No incubator module. It is now part of the platform. First, the honest framing. “Replacement” comes with an asterisk: JEP 506 explicitly does not deprecate ThreadLocal, and migration is not a goal for every use. ScopedValue replaces the dominant request-context pattern: bind an immutable value at an entry point, let callees read it, and guarantee it disappears when that operation ends. It does not replace per-thread mutable caches, accumulators that callees update for a caller, or values that must outlive the method that created them. That distinction is the whole article. Get it right and ScopedValue removes a bug class. Treat it as a nicer global variable and you will recreate the ThreadLocal mess with newer syntax. ...

2026-10-23 · 15 min · Ramesh

Structured Concurrency in Java: What Virtual Threads Didn't Fix (JEP 533, JDK 27)

Virtual threads (final since JDK 21) made blocking I/O cheap. But cheap threads didn’t fix the hard part: when you fan out to five subtasks and one fails, who cancels the other four? With ExecutorService + Future, the answer is “you, manually, and you’ll get it wrong.” That failure mode — leaked threads, swallowed errors, unobserved work — is what structured concurrency exists to kill. One warning before the code: this API is still moving. Everything below is verified against JEP 533, the seventh preview, targeting JDK 27 — and most blog examples you’ll find online show the obsolete API. Get the status table right first, then the code. ...

2026-10-08 · 8 min · Ramesh

Java Concurrency Multithreading

Thread Thread Subclass Here is an example of creating a Java Thread subclass: public class MyThread extends Thread { public void run(){ System.out.println("MyThread running"); } } To create and start the above thread you can do like this: MyThread myThread = new MyThread(); myTread.start(); You can also create an anonymous subclass of Thread like this: Thread thread = new Thread(){ public void run(){ System.out.println("Thread Running"); } } thread.start(); Runnable Interface Implementation Java Class Implements Runnable public class MyRunnable implements Runnable { public void run(){ System.out.println("MyRunnable running"); } } Anonymous Implementation of Runnable Runnable myRunnable = new Runnable(){ public void run(){ System.out.println("Runnable running"); } } Java Lambda Implementation of Runnable Runnable runnable = () -> { System.out.println("Lambda Runnable running"); }; Starting a Thread With a Runnable Runnable runnable = new MyRunnable(); // or an anonymous class, or lambda... Thread thread = new Thread(runnable); thread.start(); The Java Memory Model Here is a diagram illustrating the call stack and local variables stored on the thread stacks, and objects stored on the heap: ...

2024-07-23 · 6 min · Ramesh