Backend Development 8 min read

Exploring Spring Boot 3.2 with Java 21, Virtual Threads, and GraalVM Native Images

This article demonstrates how to use Spring Boot 3.2 together with Java 21, Project Loom virtual threads, and GraalVM native images, providing step‑by‑step setup, configuration, and code examples for controllers, async tasks, scheduled jobs, and native compilation.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Exploring Spring Boot 3.2 with Java 21, Virtual Threads, and GraalVM Native Images

Spring Boot 3.2 was released yesterday, bringing full support for Java 21, virtual threads (Project Loom), and GraalVM native images.

Java 21

Java 21, released on 19 September 2023, offers thousands of performance, stability, and security improvements that help developers increase productivity and drive innovation.

Virtual Threads

One of the most important updates is virtual threads, a feature of Project Loom. The official JEP (https://openjdk.org/jeps/444) provides a detailed explanation.

GraalVM and Native Images

GraalVM is a high‑performance JDK that can use an alternative JIT compiler to accelerate Java and JVM‑based applications. Its Native Image technology compiles Java code ahead‑of‑time into a standalone executable that includes application classes, dependencies, runtime libraries, and statically linked native code, resulting in faster startup and lower runtime memory usage compared with the JVM.

Getting Started

Install Java 21.0.1‑graal via SDKMAN:

sdk install java 21.0.1-graal

sdk default java 21.0.1-graal

Alternatively, download GraalVM manually from https://www.graalvm.org/downloads/.

Create a new Spring Boot project with Spring Initializr using Spring Boot 3.2.0, Java 21, Gradle‑Groovy, Spring Web, and GraalVM native support dependencies.

Enable virtual threads by adding the following property to application.yml or application.properties :

spring.threads.virtual.enabled: true

This makes Tomcat handle HTTP requests on virtual threads, enables @Async and Spring WebFlux blocking execution to use virtual threads, and runs @Scheduled methods on virtual threads.

Code Examples

1. Simple controller for Tomcat HTTP requests

@RestController
@RequestMapping("/test")
public class TestController {
    private static final Logger log = LoggerFactory.getLogger(TestController.class);

    @GetMapping
    public void test() {
        log.info("Rest controller method has been called {}", Thread.currentThread());
    }
}

2. Asynchronous task

@Component
public class AsyncTaskExecutorService {
    private static final Logger log = LoggerFactory.getLogger(AsyncTaskExecutorService.class);

    @Async
    public void run() {
        log.info("Async task method has been called {}", Thread.currentThread());
    }
}

3. Scheduled task (every 15 seconds)

@Component
public class SchedulerService {
    private static final Logger log = LoggerFactory.getLogger(SchedulerService.class);

    @Scheduled(fixedDelayString = "15000")
    public void run() {
        log.info("Scheduled method has been called {}", Thread.currentThread());
    }
}

Run the application:

./gradlew bootRun

Call the endpoint:

curl -X GET 'localhost:8085/test'

The logs show that the controller, async, and scheduled methods are executed on virtual threads belonging to the common ForkJoinPool.

According to JEP 444, the virtual‑thread scheduler is a work‑stealing ForkJoinPool that runs in FIFO order, with parallelism equal to the number of platform threads available for scheduling virtual threads.

Building a GraalVM Native Image

Compile the native image (this may take several minutes) and run it:

./gradlew nativeCompile

./build/native/nativeComplie/app

The native executable starts much faster and uses less runtime memory, confirming the advantages of GraalVM native images over the traditional JVM.

The full source code used in this article is available at https://github.com/egor-ponomarev/spring-boot3.2-with-graalvm-virtual-threads-example.

Conclusion

Spring Boot 3.2 brings the long‑awaited support for virtual threads and GraalVM native images, allowing developers to write code with Go‑like performance and scalability while staying within the rich JVM ecosystem. However, not all libraries are yet compatible with virtual threads, so developers should verify library behavior before adopting them in production.

BackendSpring BootVirtual ThreadsGraalVMnative-imageJava 21
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.