How to Enable Java Virtual Threads in Spring Boot 3.1 and Boost Performance
This tutorial shows how to activate Java 21 virtual threads in Spring Boot 3.1 (and earlier versions), provides full configuration code for Tomcat, Undertow and Spring async, and demonstrates a performance test where concurrency gains reduce total execution time by over five times.
1. Introduction
Java 21 has been released. In Spring Boot 3.2 you can enable virtual threads by setting
spring.threads.virtual.enabled=true.
Although Spring Boot 3.2 is not yet officially released, you can still enable virtual threads in earlier versions such as Spring Boot 3.1.4 and even 2.7.15. The following sections demonstrate how.
2. Enabling Virtual Threads
In Spring Boot 3.1.4 you need to configure virtual threads manually. First, configure Tomcat:
<code>@Configuration(proxyBeanMethods = false)
public class VirtualThreadConfiguration {
@Bean
public TomcatProtocolHandlerCustomizer<ProtocolHandler> tomcatProtocolHandlerCustomizer() {
return protocolHandler -> protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
}
}
</code>Note: The VirtualThreadConfiguration class should not be annotated with @AutoConfiguration , otherwise it may not take effect.
Then create a simple API controller:
<code>@RestController
public class ApiController {
@GetMapping
public String api() throws InterruptedException {
// Simulate 300 ms latency
TimeUnit.MILLISECONDS.sleep(300);
return LocalDateTime.now() + " Thread: " + Thread.currentThread();
}
}
</code>Request and response example:
<code>$ curl -s http://localhost:8080/
2023-09-22T17:36:43.183296300 Thread: VirtualThread[#70]/runnable@ForkJoinPool-1-worker-4
</code>Enabling virtual threads for Undertow:
<code>@Bean
public UndertowDeploymentInfoCustomizer undertowDeploymentInfoCustomizer() {
return deploymentInfo -> deploymentInfo.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
}
</code>Configuring Spring’s async executor to use virtual threads:
<code>@Bean
public AsyncTaskExecutor asyncTaskExecutor() {
return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
}
</code>3. Performance Results
A simple load test with
go-wrkwas performed using 10 000 requests at concurrency levels of 100, 300, 500 and 1 000. The total execution time decreased as concurrency increased, showing a clear advantage of virtual threads. At 1 000 concurrent requests the total time was reduced by more than five times.
4. Real‑World Project
Using the PIG microservice development platform on the JDK 21 snapshot branch (Java 21, Spring Boot 3.2, Spring Cloud 2023), a stress test was run against the OAuth2.0 token endpoint.
With 200 concurrent requests, enabling virtual threads more than doubled both response time and throughput.
5. Conclusion
If your service receives a very high volume of requests and individual endpoints have noticeable latency, upgrading to Java 21 and enabling virtual threads is a worthwhile option.
Virtual threads are a lightweight threading model that can dramatically improve the performance and scalability of multithreaded applications.
They allow a large number of threads to run concurrently without consuming excessive system resources. Because creation and destruction costs are lower than traditional OS threads, services can respond faster, handle more concurrent requests, increase overall throughput, and reduce client‑side waiting time.
Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.