Using Java Virtual Threads in Spring Boot: Performance Comparison with Traditional Threads
This article explains what Java virtual threads are, how they differ from regular OS threads, demonstrates configuring Spring Boot to use them, and presents performance benchmarks showing virtual threads dramatically outperform traditional threads in both async service calls and simple HTTP requests.
Java virtual threads, introduced in Java 19, provide lightweight, user‑level threads similar to Go's goroutines, allowing a single OS thread to multiplex thousands of virtual threads.
Unlike regular threads that are scheduled directly by the operating system, virtual threads are managed by the JVM and scheduled on top of platform threads, resulting in far lower memory and scheduling overhead; millions of virtual threads can be created when memory permits.
To enable virtual threads in a Spring Boot application (Java 20, Spring Boot 3.1.2), add the following configuration:
/**
* Enable virtual threads by setting spring.virtual-thread=true; set to false to use regular threads.
*/
@Configuration
@ConditionalOnProperty(prefix = "spring", name = "virtual-thread", havingValue = "true")
public class ThreadConfig {
@Bean
public AsyncTaskExecutor applicationTaskExecutor() {
return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
}
@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {
return protocolHandler -> {
protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
};
}
}With this setup, the default async thread pool and Tomcat’s request‑handling thread pool are replaced by virtual threads.
Performance comparison of an @Async service that sleeps for 50 ms (simulating I/O) shows a dramatic speedup:
@Service
public class AsyncService {
/**
* @param countDownLatch used for testing
*/
@Async
public void doSomething(CountDownLatch countDownLatch) throws InterruptedException {
Thread.sleep(50);
countDownLatch.countDown();
}
} @Test
public void testAsync() throws InterruptedException {
long start = System.currentTimeMillis();
int n = 100000;
CountDownLatch countDownLatch = new CountDownLatch(n);
for (int i = 0; i < n; i++) {
asyncService.doSomething(countDownLatch);
}
countDownLatch.await();
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "ms");
}Using regular threads the test takes about 678 seconds, whereas virtual threads finish in roughly 3.9 seconds—an improvement of nearly 200×.
A similar benchmark for a simple HTTP GET endpoint that also sleeps 50 ms demonstrates that regular threads incur median and high‑percentile latencies above 150 ms under 500 concurrent requests, while virtual threads keep the maximum latency below 100 ms.
@RequestMapping("/get")
public Object get() throws Exception {
Thread.sleep(50);
return "ok";
}The results indicate that virtual threads excel in I/O‑bound workloads where threads spend most of their time waiting, which is typical for web services, databases, caches, and external HTTP calls. For CPU‑bound tasks the benefit may be smaller.
In conclusion, adopting Java virtual threads in Spring Boot can dramatically reduce latency and resource consumption for I/O‑intensive applications, and it is advisable for projects still on older Java versions to upgrade to leverage this capability.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
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.
