CONCEPT Cited by 1 source
Virtual thread¶
A virtual thread (VT) is a JVM-managed lightweight thread that multiplexes onto a small pool of OS-backed worker threads — the carrier threads — via continuations. Introduced in Java 19 as preview and stabilised in Java 21 via JEP 444.
The model¶
"A virtual thread is not mapped 1:1 to a dedicated OS-level thread. Rather, we can think of it as a task that is scheduled to a fork-join thread pool. When a virtual thread enters a blocking call, like waiting for a
Future, it relinquishes the OS thread it occupies and simply remains in memory until it is ready to resume. In the meantime, the OS thread can be reassigned to execute other VTs in the same fork-join pool. This allows us to multiplex a lot of VTs to just a handful of underlying OS threads." (Source: sources/2024-07-29-netflix-java-21-virtual-threads-dude-wheres-my-lock)
A VT is "mounted" on a carrier while executing and "unmounted" while waiting. Mount/unmount is mechanically driven by continuations — the JVM captures the VT's execution state (frame stack, program counter) to the heap on unmount and restores it on mount.
Why it matters¶
The classical JVM concurrency ceiling is the platform-thread pool size (typically ~200 in Tomcat defaults). With VTs, the ceiling becomes "how many VT tasks can the JVM multiplex over its carrier pool" — which can be millions for low-contention workloads (I/O-bound web handlers that spend most of their time waiting on downstream RPCs).
This is the selling point — VTs let you keep the simple blocking-per-request programming model (patterns/blocking-model-per-request-tomcat) while scaling past the platform-thread-pool cap.
The hazard — pinning¶
VTs cannot unmount from their carrier in certain JVM
states. The most important case: a blocking call inside a
synchronized block pins the VT to its carrier for the entire
block. See concepts/virtual-thread-pinning.
If enough VTs pin simultaneously, the carrier-thread pool is exhausted; the JVM can still create VTs, but none can mount. New request-VTs queue behind the pinned ones, and the application appears to hang from the outside.
Seen in¶
- sources/2024-07-29-netflix-java-21-virtual-threads-dude-wheres-my-lock
— Canonical wiki introduction. Netflix's 2024 migration to
Java 21 enabled VTs alongside generational ZGC; production
Spring Boot 3 + embedded Tomcat services hung with
closeWaitpile-up when four VTs pinned insidesynchronizedon the Brave span-finish path exhausted all carrier threads on 4-vCPU instances.
Related¶
- systems/java-21-virtual-threads — The runtime feature.
- concepts/virtual-thread-pinning — The critical failure mode.
- concepts/carrier-thread — The OS-thread resource VTs consume during execution.
- concepts/fork-join-pool — The scheduler pool underneath.
- companies/netflix — Canonical adopter documented on the wiki.