Backend Development 7 min read

Java 21 Virtual Threads: Basics, Spring Boot Integration, and Performance Comparison

This article introduces Java 21 virtual threads, explains their lightweight and automatically managed nature, demonstrates basic creation and Spring Boot configuration, and presents performance experiments comparing traditional and virtual threads in both CPU‑bound and HTTP request scenarios.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Java 21 Virtual Threads: Basics, Spring Boot Integration, and Performance Comparison

Virtual threads are a new feature introduced in Java 21 that simplify concurrent programming by providing a lightweight, JVM‑managed alternative to traditional operating‑system threads, enabling the creation of hundreds of thousands of threads with low memory overhead.

Basic Usage of Virtual Threads

Creating a virtual thread is straightforward; you can start it directly or create it in an unstarted state and launch it later.

Thread virtualThread = Thread.ofVirtual().start(() -> {
    System.out.println("Virtual thread is running");
});
System.out.println("Main thread is running");

Virtual threads also support delayed start and naming:

Thread virtualThread = Thread.ofVirtual()
    .name("VirtualThread")
    .unstarted(() -> System.out.println("Virtual thread running"));
virtualThread.start();
virtualThread.join(); // wait for completion

Using Virtual Threads in Spring Boot

To use virtual threads in a Spring Boot project, ensure the Java version is 21 or higher and enable preview features in pom.xml :

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>21</source>
        <target>21</target>
        <compilerArgs>
            <arg>--enable-preview</arg>
        </compilerArgs>
    </configuration>
</plugin>

Enable performance monitoring in application.properties :

management.endpoints.web.exposure.include=health,info,metrics

Configure Tomcat to use a virtual‑thread executor:

@Bean
public TomcatProtocolHandlerCustomizer
protocolHandlerVirtualThreadExecutorCustomizer() {
    return protocolHandler -> protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
}

Experiment: Traditional Threads vs. Virtual Threads

1. Creating 100,000 Threads

Traditional threads:

for (int i = 0; i < 100_000; i++) {
    Thread thread = new Thread(() -> System.out.println(i));
    thread.start();
    thread.join();
}

Execution time ≈ 18.6 seconds.

Virtual threads:

for (int i = 0; i < 100_000; i++) {
    Thread thread = Thread.ofVirtual().unstarted(() -> System.out.println(i));
    thread.start();
    thread.join();
}

Execution time ≈ 3.7 seconds, a performance gain of nearly 500 %.

2. HTTP Request Performance

In a high‑concurrency scenario (1,600 HTTP requests with 400 concurrent threads), the following results were observed:

Traditional threads: 9.659 seconds, 165.65 requests/second.

Virtual threads: 7.912 seconds, 202.22 requests/second.

Virtual threads significantly improve throughput and reduce response time.

Other Java Performance Techniques

Parallel Streams : Use parallelStream() for CPU‑intensive tasks to leverage multiple cores. List numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.parallelStream().forEach(number -> { System.out.println(number * 2); });

Asynchronous Programming with CompletableFuture : Suitable for I/O‑bound tasks. CompletableFuture future = CompletableFuture.runAsync(() -> { // asynchronous task System.out.println("Async task completed"); }); future.join(); // wait for completion

Database Query Optimization : Reduce query count and use caching (e.g., Redis) to minimize I/O.

Memory Management : Employ object pools such as Apache Commons Pool to reuse resources and lower garbage‑collection overhead.

Conclusion

Virtual threads revolutionize Java concurrency by simplifying thread management and boosting performance in high‑load scenarios.

Hundreds of thousands of virtual threads can be created without degrading application performance.

Integrating virtual threads into Spring Boot requires only a few configuration steps and yields noticeable speed improvements.

Additional optimizations—parallel streams, CompletableFuture, query caching, and object pooling—further enhance Java application performance.

By applying these techniques, Spring Boot applications can achieve stronger performance and lower latency under heavy concurrency.

JavaperformanceconcurrencySpring BootVirtual Threads
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

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.