For decades, Java concurrency meant platform threads: OS-backed, heavy (1 MB stack per thread), and limited to thousands per process. I/O-bound backends had to rely on thread pools, async APIs, or reactive frameworks to scale. Java 21 delivers virtual threads as a production feature — lightweight threads that make thread-per-request the default again.
Project Loom and Virtual Threads
Project Loom introduces virtual threads (preview in 19, GA in 21). They are scheduled by the JVM onto a small pool of carrier (platform) threads. When a virtual thread blocks — on I/O, locks, or Thread.sleep — it is unmounted; the carrier runs another virtual thread. Blocking is cheap; you can create millions of virtual threads.
Virtual Threads vs. Platform Threads
- Memory — Virtual threads use ~1 KB vs. ~1 MB per platform thread
- Context switching — Unmounting is in-process; no kernel involvement
- Programming model — Write synchronous, blocking code; the runtime handles concurrency
- Compatibility — Same
ThreadandExecutorServiceAPIs; minimal migration effort
Throughput Improvements
Web servers and APIs that spend most of their time waiting on databases, HTTP calls, or message queues see the biggest gains. A typical servlet or Spring MVC app can switch from a 200-thread pool to 10,000+ virtual threads. Benchmarks often show 2–5x higher throughput at the same resource footprint, with lower latency under load because requests are not queued behind a small pool.
Migration Path
Enable virtual threads with ExecutorService.newVirtualThreadPerTaskExecutor() or by configuring your framework (Spring Boot 3.2+ supports virtual thread executors out of the box). Replace @Async or reactive chains with plain blocking code. Watch for thread-local and synchronized usage: both can pin virtual threads to carriers and reduce scalability if overused. Prefer ReentrantLock over synchronized when locking is necessary.
Real-World Performance Gains
Teams report 3–4x improvement in requests-per-second for I/O-heavy workloads with no code rewrite beyond executor configuration. Database-bound services benefit most. The JVM and frameworks (Netty, Tomcat, Spring) have been optimized for virtual threads; the ecosystem is ready. For backend developers, Java 21 virtual threads offer the simplicity of thread-per-request with the scalability of reactive programming.