Backend Development 7 min read

Boost SpringBoot Performance: Harness Java Virtual Threads for 200× Speedup

This article explains Java virtual threads, compares them with regular threads, shows how to enable them in SpringBoot, and presents performance tests that reveal up to a 200‑fold reduction in latency for IO‑bound workloads.

macrozheng
macrozheng
macrozheng
Boost SpringBoot Performance: Harness Java Virtual Threads for 200× Speedup

What Are Virtual Threads

Virtual threads are a feature added in Java 19, similar to Go's goroutines, providing a lightweight threading model that Java developers have long awaited.

Differences Between Virtual and Regular Threads

Virtual threads are "fake" threads managed by the JVM rather than the operating system, allowing a single OS thread to schedule thousands of virtual threads. They consume far less memory, enabling the creation of millions of threads when resources permit.

Using Virtual Threads in SpringBoot

By replacing the default asynchronous thread pool and the HTTP handling thread pool with virtual threads, SpringBoot applications can achieve dramatic performance gains.

Configuration

The Java version used is

java-20.0.2-oracle

and SpringBoot version is

3.1.2

.

Enable virtual threads with the following configuration:

<code>@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());
        };
    }
}
</code>

@Async Performance Comparison

An asynchronous service that sleeps for 50 ms (simulating I/O) is tested by invoking the method 100 000 times.

<code>@Service
public class AsyncService {
    @Async
    public void doSomething(CountDownLatch countDownLatch) throws InterruptedException {
        Thread.sleep(50);
        countDownLatch.countDown();
    }
}
</code>
<code>@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");
}
</code>

Results:

Regular threads:

678 seconds

(over 10 minutes)

Virtual threads:

3.9 seconds

– roughly 200× faster.

HTTP Request Performance Comparison

A simple GET endpoint that sleeps 50 ms is stress‑tested with JMeter (500 concurrent threads, 10 000 requests).

<code>@RequestMapping("/get")
public Object get() throws Exception {
    Thread.sleep(50);
    return "ok";
}
</code>

Results for regular threads show median and 90/95/99 percentiles exceeding 150 ms because OS threads are scarce and block while waiting.

Virtual threads keep the maximum response time below 100 ms, demonstrating far better resource utilization.

Conclusion

Virtual threads provide a clear performance advantage for I/O‑bound scenarios, which constitute the majority of typical web applications. They are less beneficial for CPU‑bound workloads. Leveraging them in SpringBoot can dramatically reduce latency and improve scalability.

JavaperformanceconcurrencySpringBootVirtual Threads
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.