What are Virtual Threads
The Thread-per-Request Problem
A classic Spring MVC / Tomcat server gives each request one platform thread (an OS thread). Each platform thread costs about 1 MB of stack and an OS context switch, so a server tops out around a few thousand threads. Most of that time the threads just wait for the database or an HTTP call.
Virtual threads (final in Java 21, Project Loom) are threads managed by the JVM, not the OS. They are cheap (a few hundred bytes to start), so you can have millions. When a virtual thread blocks on I/O, the JVM unmounts it and the underlying OS thread (the carrier) runs another virtual thread.
How They Run
virtual threads (millions) V1 V2 V3 V4 V5 V6 ...
│ │ │ │
mount / unmount ▼ ▼ ▼ ▼
carrier threads (≈ CPU cores) ┌────┐ ┌────┐ ┌────┐ ┌────┐
(ForkJoinPool) │ C1 │ │ C2 │ │ C3 │ │ C4 │
└────┘ └────┘ └────┘ └────┘
V1 calls socket.read() → V1 is parked (its stack saved on the heap) → C1 runs V5What They Are Not
Note: Virtual threads do not make CPU-heavy code faster: the number of cores is the same. They help throughput for I/O-bound work (web requests, DB calls, REST calls) where threads mostly wait.