| Metric | Platform Threads | Virtual Threads |
|---|
Simulated I/O-bound workload. Real throughput depends on database connection pool size, downstream service limits, and GC pressure. Modernising a Spring Boot service to Java 21? Get in touch.
InputStream.read()), it parks — unmounts from its carrier OS thread. The carrier is immediately free to run another virtual thread. No kernel context switch, no stack allocation held idle.spring.threads.virtual.enabled=true in application.yml — that's the entire migration for most services. Spring Boot 3.2+ wires Tomcat, @Async, @Scheduled, and Spring Security's SecurityContextHolder automatically. One property, production-safe from day one.synchronized blocks pin the carrier thread — replace with ReentrantLock for hot paths. Connection pools (HikariCP) still cap DB connections — virtual threads don't create more connections, they just wait more efficiently. CPU-bound tasks gain nothing — use ForkJoinPool for those.About this demo
Platform threads are OS-managed: each one reserves a stack (typically 512 KB–1 MB), and the OS scheduler is responsible for switching between them. Under I/O-bound load — where threads spend most of their time blocked waiting for a database or network response — the thread pool exhausts long before CPU does, and new requests queue or are rejected.
Java 21 virtual threads are JVM-managed fibres with near-zero overhead. When a virtual thread blocks on I/O, the JVM parks it and unmounts it from its carrier platform thread, freeing that carrier to run other work. You can create millions of virtual threads without running out of OS resources. Drag the load slider to watch where each model breaks — the inflection point is usually visible within a few seconds.