🧵 Virtual Threads in Spring Boot 3.3+: When to Enable, When to Walk Away
Spring Boot 3.3 made virtual threads first-class with spring.threads.virtual.enabled=true. It sounds like free concurrency, but production doesn't care about hype. Let's break down where Project Loom shines, where it burns, and how to roll it out without waking up on-call.
⚙️ The One-Line Switch
spring:
threads:
virtual:
enabled: true
This flips Tomcat/Undertow to mount request handlers on virtual threads instead of platform threads. Throughput jumps for I/O-bound workloads. But CPU-bound work? You're just adding scheduling overhead.
🚦 Production Checklist
- Audit for
synchronizedblocks & native JNI calls (they pin carrier threads) - Replace thread-local MDC with
Scopesor pass context explicitly - Benchmark with realistic payloads, not
curl localhost:8080/health - Set
-Djdk.tracePinnedThreads=shortin dev to catch blockers early - Keep connection pools sized for virtual threads (HikariCP auto-tunes, but verify
maximumPoolSize)
💡 Verdict
Enable it for gateway services, API aggregators, and database-heavy apps. Keep platform threads for CPU crunchers (video processing, ML inference). Virtual threads aren't magic—they're a scalability tool. Treat them like one.
Tags:
spring boot