When it shines
- IO-heavy workloads with many concurrent requests.
- Simplifies thread-per-request code without callback hell.
- Great for blocking JDBC (with drivers that release threads), HTTP clients, and file IO.
Caveats
- Avoid blocking operations that pin VTs (synchronized blocks, some native calls).
- Watch libraries that block on locks; prefer async-friendly drivers when possible.
- Pinning shows as carrier thread exhaustion; monitor.
Usage
- Executors:
Executors.newVirtualThreadPerTaskExecutor(). - For servers (e.g., Spring): set
spring.threads.virtual.enabled=true(Spring Boot 3.2+). - Keep per-request timeouts; use structured concurrency where possible.
Observability
- Metrics: carrier thread pool usage, VT creation rate, blocked/pinned threads.
- Profiling: use JDK Flight Recorder; check for pinning events.
Checklist
- Dependencies vetted for blocking/pinning.
- Timeouts on all IO; circuit breakers still apply.
- Dashboards for carrier thread utilization and pinning.
- Load test before prod; compare throughput/latency vs platform threads.