We are planning to migrate our blocking I/O services to Java 21 to leverage Virtual Threads. In a standard Spring Boot 3.2+ project, what is the exact configuration needed to ensure that the underlying Tomcat or Undertow web server utilizes virtual threads instead of the traditional platform thread pool? Does this change how we handle @Async tasks or scheduled jobs?
3 answers
To enable Virtual Threads in Spring Boot 3.2 or later, the configuration is actually very simple but powerful. You just need to set spring.threads.virtual.enabled=true in your application.properties. This single property tells Spring Boot to use the VirtualThreadTaskExecutor for both the embedded Tomcat server and for any @Async methods. In my experience migrating a FinTech service last year, this allowed us to handle nearly 10x the concurrent connections without increasing our memory footprint. However, be cautious with "ThreadLocals" as they behave differently with virtual threads. You should also audit your third-party libraries for any "synchronized" blocks that might "pin" the carrier thread, which can negate the performance benefits of using Project Loom.
Are you seeing any "pinning" issues with your current JDBC drivers when using virtual threads, or have you already upgraded to the latest reactive-friendly drivers for your database?
The beauty of Virtual Threads is that you don't need WebFlux for high concurrency anymore. It brings the simplicity of synchronous code back to high-performance applications.
Exactly, Laura. It effectively kills the "Reactive vs. Servlet" debate for 90% of use cases. Staying with the imperative model makes debugging and stack traces much easier for the team.
Charles, we are still on an older MySQL driver, and I suspect pinning might be an issue. We saw some weird latency spikes during our initial load tests. Do you recommend moving to the R2DBC driver instead, or is there a specific version of the standard JDBC driver that plays nicer with virtual threads? We want to avoid a full reactive rewrite if we can just keep our existing JPA repositories but optimize the underlying thread handling.