Virtual Threads in Springboot 3.2

Navod Dilshan
Nerd For Tech
Published in
5 min readJan 5, 2024

--

With the recent launch of Spring Boot 3.2, there’s a standout feature stealing the spotlight — virtual threads. The main focus is on boosting how the program runs, aligning with the broader goal of improving efficiency during runtime. This article dives into the significance of virtual threads, underlining their seamless integration with Java version 21 for a smoother development experience

Spring MVC and Thread per Request Model

Spring MVC applications traditionally operate on a thread per request model. When a client communicates with a Java application, a thread is spawned to handle the request. This thread, often referred to as a platform thread, represents a finite resource tied to the operating system thread. However, issues arise when blocking operations, such as database calls or HTTP service requests, tie up these threads, leading to decreased throughput and potential application slowdowns.

Thread per Request Model

What is Virtual Threads?

Virtual threads, introduced at the Java 21 JDK level, provide an innovative solution to the challenges posed by traditional threads. Unlike platform threads, virtual threads offer an illusion of infinite scalability. They are lightweight threads capable of performing tasks independently, eliminating the need to tie themselves to a platform thread. Virtual threads shine when handling blocking operations, such as HTTP service calls or database queries, as they don’t hang up the platform thread.

Here you can see how the JAVA thread and virtual threads connect with operating system threads.

JAVA Threads
Virtual Threads

Why we use Virtual Threads in Spring?

Virtual threads offer a scalable solution without the need for additional hardware. By decoupling from platform threads, applications can spawn thousands or even millions of virtual threads to perform tasks concurrently, significantly improving scalability.

Let’s create two Spring Boot applications together to explore how virtual threads work in practice.

01) The first application represents a blocking scenario, simulating HTTP communication with delays, highlighting the challenges of traditional threads in handling such operations.

Spring Initializr

Navigate to Spring Initializr in your web browser.

Project Configuration

When initiating your Spring Boot project through Spring Initializr, opt for “Maven” as your project type. Choose Spring Boot version 3.2 to leverage the latest enhancements, and set the Java version to 21 to ensure compatibility with contemporary Java features.After that add Spring Web dependency into your project.

Click on the “Generate” button to generate the project and open the project with your favorite code editor.

Configuring Application Properties

configure the server port as follows in “application.properties”

server.port=8081

Creating a Controller

Now, let’s create a new Java class named “BlockController” to set up blocking endpoints and run the program.

package com.imnavod.virtual.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class BlockController {

private static final Logger log = LoggerFactory.getLogger(BlockController.class);

@GetMapping("/block/{seconds}")
public void block(@PathVariable Integer seconds) throws InterruptedException{
Thread.sleep(seconds*1000);
log.info("Sleep for {} seconds ",seconds);
}
}

Using Thread.sleep(seconds * 1000) adds a specified waiting time after calling the endpoint, where the desired duration is represented in seconds.
This application has just created an endpoint with a delay, simulating either network latency or processing delay. In real-world scenarios, when a client initiates an API request, the response is not instantaneous, and there is typically a delay before receiving the result.

02) In the second application, we’ll experience the enhanced capabilities of virtual threads by enabling them in Spring Boot 3.2.

Generate and open the project using the same approach as in the first application.

Configuring Application Properties

configure the server port as follows in “application.properties”

server.port=8082

Creating a Controller

Create a Java class named “HomeController” to define endpoints. Subsequently, implement a GET request to invoke another HTTP request from a separate service. This setup enables us to call our first application using this GET method.

Within this method, we utilize the RestClient in Spring Boot to make an HTTP call. This RestClient functions as a synchronous HTTP client, making it suitable for a multi-threaded program.

package com.imnavod.virtual.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestClient;

@RestController
public class HomeController {

private final static Logger logger = LoggerFactory.getLogger(HomeController.class);

private final RestClient restClient;
public HomeController(RestClient.Builder builder){
this.restClient=builder.baseUrl("http://localhost:8081").build();

}
@GetMapping("/block/{seconds}")
public String home(@PathVariable Integer seconds){
ResponseEntity<Void> result = restClient.get()
.uri("/block/"+seconds)
.retrieve()
.toBodilessEntity();

logger.info("{} on {}",result.getStatusCode(),Thread.currentThread());
return Thread.currentThread().toString();

}


}

In our machines, resources are limited, and we cannot allocate an unlimited amount to any application. Therefore, it is essential to impose restrictions on the resources accessible to the application. As a measure, we set a maximum limit of 10 threads for the server to utilize.

We are adding another configuration to the “application.properties”.

server.port=8082
server.tomcat.threads.max=10

I‘m using Apache Benchmark to concurrently send requests to the server and obtain a performance benchmark. This is how we send 60 requests, 20 concurrently, with a 2-second delay for each request. We expect the execution of all 60 requests to take 12 seconds. This is because if we send 20 requests concurrently, the server can’t process all 20 requests at once. This limitation is due to restricting it to 10 threads.

ab -n 60 -c 20 http://localhost:8082/httpbin/block/2

You can see the following result in the IDE console for each reqeust.

2024-01-06T02:34:49.410+05:30  INFO 8888 --- [nio-8082-exec-2] c.imnavod.virtual.thread.HomeController  : 200 OK on Thread[#38,http-nio-8082-exec-2,5,main]
Benchmark test without enable virtual threads

Let’s enable virtual threads and observe the performance gain from this existing feature in Spring Boot 3.2. To do that, go to the “application.properties ” file and make the following changes.

server.port=8082
spring.threads.virtual.enabled=true

Run the same benchmark test as earlier. If your virtual threads are enabled successfully, you can see the log for each request in the IDE console as follows.

2024-01-06T02:39:34.204+05:30  INFO 22348 --- [omcat-handler-0] c.imnavod.virtual.thread.HomeController  : 200 OK on VirtualThread[#40,tomcat-handler-0]/runnable@ForkJoinPool-1-worker-1
Benchmark test after enable virtual threads

You can clearly see the difference in how virtual threads enhance performance.

Before enable virual threads — 14.286 seconds
After enable virual threads — 8.340 seconds

Conclusion

Summing up, this artcel looks at how Virtual Threads in Java can boost Spring Boot application performance. However, they may not be the best choice for tasks that need a lot of processing power or if you’re already using asynchronous programming. The key takeaway is to know when to use Virtual Threads for the best results. By discussing challenges with asynchronous programming and showing real-world examples, the article aims to help you understand how to make the most of Virtual Threads and improve your Spring Boot applications.

code- https://github.com/navoddilshan9/spring-boot-virtual-threads.git

Happy coding!!!!

--

--