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.