Boost Java Concurrency with Project Loom: A Hands‑On Guide to Virtual Threads
Learn how Project Loom’s virtual threads can replace heavyweight OS threads in Java Spring Boot applications, enabling one‑thread‑per‑request models, improving throughput under high concurrency, with step‑by‑step setup, code samples, and performance comparisons across 100‑, 300‑ and 500‑thread tests.
What Is Project Loom?
Project Loom is an Oracle initiative aimed at dramatically reducing the effort required to write, maintain, and observe high‑throughput concurrent applications. It introduces lightweight virtual threads that are managed by the JVM instead of the operating system, making a one‑thread‑per‑request model feasible without sacrificing throughput. Virtual threads are available in Spring Boot 3.1.
How to Use Virtual Threads
Choosing the Java Version
Virtual threads were introduced in Java 19. The author uses the Azul Zulu distribution version 20.30.11 on a Mac M1.
Creating a Test Project
Generate a Spring Boot project via Spring Initializr or an IDE, add the
spring-webdependency, and ensure you use Spring Boot 3.1 with Java 20.
Enabling Virtual Thread Support
Virtual threads are disabled by default in Java 19 and must be enabled via Maven compiler arguments.
<code><plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin></code>Enable virtual threads via a bean
<code>@Bean
TomcatProtocolHandlerCustomizer<?> threadExecutorCustomizer() {
return protocolHandler -> protocolHandler.setExecutor(
Executors.newVirtualThreadPerTaskExecutor());
}</code>This bean customizes the Tomcat protocol handler to use an executor backed by virtual threads, allowing many concurrent tasks with minimal resource cost.
Adding a Test Endpoint
<code>@Slf4j
@RequestMapping
@RestController
public class DemoController {
@GetMapping("/")
public String demo() {
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
log.error(e.getMessage());
}
return "Current Thread Name: " + Thread.currentThread();
}
}
</code>Getting Started
Use
Thread.currentThread()to verify that the request is handled by a virtual thread.
Performance Test Comparison
100‑Thread Test
Without virtual threads
Throughput: 300 req/s
With virtual threads
Throughput: 300 req/s
300‑Thread Test
Without virtual threads
Throughput: 650 req/s
With virtual threads
Throughput: 950 req/s
500‑Thread Test
Without virtual threads
Throughput: 650 req/s
With virtual threads
Throughput: 1500 req/s
Chart Output
Conclusion
Virtual threads prove especially beneficial for blocking operations. As the number of concurrent requests grows, the performance advantage of virtual threads becomes increasingly evident. The tests were conducted without any additional Spring Boot tuning or optimization.
References
[1] Azul Zulu distribution 20.30.11: https://www.azul.com/downloads/?version=java-20-sts&os=macos&architecture=arm-64-bit&package=jdk#zulu
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.