Virtual Threads with Spring Boot made simple

In this article we will learn how to use Virtual Threads which is an exciting new feature that you can use to simplify the creation of reactive applications in Java. We will show a step-by-step guide to run a simple Web application with Spring Boot and Virtual Threads.

Firstly, Java Virtual threads are lightweight threads that simplify the creation of concurrent applications which require high-throughput and reduced memory foot print.

Since Java 19 we can easily start threads as “virtual”:

var thread = Thread.startVirtualThread(() -> { ... });

That’s all. The JVM ensures that these VirtualThreads are automatically mapped to OS threads. Typically one per CPU core. In this VirtualThread you can place blocking calls, locks and sleeps in a synchronous manner to your heart’s content. We should no longer worry about the competition for resources.

To get some more details about Virtual Threads in Java we recommend this Introduction to Virtual Threads.

That being said, in the next section we will show how to create a simple Spring Boot 3.2 project featuring Virtual Threads from within a Web application.

Setting up the Spring Boot application

Reach the Spring Boot initializer and choose to create a basic Spring Boot 3.2 application which includes the Web dependency and uses Java 21 as runtime:

spring boot 3.2 virtual threads example

If you are using Java 19 instead, make sure that you enable the Preview Features in your Maven compiler plugin:

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

Next, let’s add a simple Controller Class which serves the only purpose to see the current Thread:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/virtual")
public class DemoController {

    @GetMapping("/name")
    public String getThreadName() {
        return Thread.currentThread().toString();
    }

}

Configuring Tomcat to use Virtual Threads

Next, to configure the Tomcat Web Server to serve HTTP requests using Virtual Threads (instead of default Java Threads), we have to customize the Protocol Handler as follows:

import java.util.concurrent.Executors;

import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

 
@Configuration
public class VirtualThreadConfig {

	@Bean
	TomcatProtocolHandlerCustomizer<?> tomcatProtocolHandlerCustomizer() {
		return protocolHandler -> {
			protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
		};
	}
}

With this configuration in place, the new task executor, which Spring uses in various places for asynchronous calls, receives a new VirtualThread instead of a standard Java Thread.

You can test that Virtual Threads are working by executing a curl to the Controller:

$ curl http://localhost:8080/virtual/name
VirtualThread[#41]/runnable@ForkJoinPool-1-worker-1

Conclusion

Virtual threads offer an exciting solution to improve performance and scalability for Spring developers. With minimal code changes you can greatly simplify the creation of reactive applications in Java and with Spring Boot.

Source code for this tutorial: https://github.com/fmarchioni/masterspringboot/tree/master/various/virtual-threads

Found the article helpful? if so please follow us on Socials
Twitter Icon       Facebook Icon       LinkedIn Icon       Mastodon Icon