Compiling virtual thread applications into native executables
In another blog post, we have seen how you can implement a CRUD application with Quarkus to utilize virtual threads. This post will show how you can compile such an application into a native executable.
Installing GraalVM 21
To compile a Quarkus application leveraging virtual threads into a native executable, you need a GraalVM version supporting Java 21. You can download it from GitHub.
Alternatively, you can use the SDKMAN tool to install it:
> sdk install java 21-graalce
Downloading: java 21-graalce
In progress...
Repackaging Java 21-graalce...
Done repackaging...
Cleaning up residual files...
Installing: java 21-graalce
Done installing!
Do you want java 21-graalce to be set as default? (Y/n): n
Once installed, make sure the GRAALVM_HOME
environment variable points to the GraalVM installation directory:
> export GRAALVM_HOME=$HOME/.sdkman/candidates/java/21-graalce
Compiling the application into a native executable
We will reuse the CRUD application developed in a previous blog post. The source code is located in the virtual-threads-demos GitHub repository. Note that while we are using the CRUD application, the same approach can be used with any Quarkus application leveraging virtual threads, including the other demos from the repository.
First make sure you use Java 21+ and that the GRAALVM_HOME
environment variable points to the GraalVM installation directory.
Then, in the pom.xml
file, add the native
profile:
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
The native
profile is activated when the native
property is set.
So, compile the application with:
> mvn clean package -Dnative
The compilation takes a few minutes. Once done, you can run the application:
-
1) First, start the database:
> docker run --ulimit memlock=-1:-1 -d -it --rm=true --memory-swappiness=0 \
--name postgres-quarkus-demo -e POSTGRES_USER=restcrud \
-e POSTGRES_PASSWORD=restcrud -e POSTGRES_DB=rest-crud \
-p 5432:5432 postgres:15-bullseye
-
2) Then, start the application:
> ./target/crud-example-1.0.0-SNAPSHOT-runner
You get:
> ./target/crud-example-1.0.0-SNAPSHOT-runner
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2023-10-17 09:44:34,925 INFO [io.quarkus] (main) crud-example 1.0.0-SNAPSHOT native (powered by Quarkus 3.4.1) started in 0.072s. Listening on: http://0.0.0.0:8080
2023-10-17 09:44:34,925 INFO [io.quarkus] (main) Profile prod activated.
2023-10-17 09:44:34,925 INFO [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache, hibernate-validator, jdbc-postgresql, narayana-jta, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, vertx]
Then, open the application in a browser (http://localhost:8080) and start adding, updating, and completing tasks. You will see in the logs that the processing of these requests are executed on virtual threads:
2023-10-17 10:15:09,992 INFO [org.acm.cru.TodoResource] (quarkus-virtual-thread-0) Called on VirtualThread[#78,quarkus-virtual-thread-0]/runnable@ForkJoinPool-5-worker-1
2023-10-17 10:15:13,136 INFO [org.acm.cru.TodoResource] (quarkus-virtual-thread-1) Called on VirtualThread[#85,quarkus-virtual-thread-1]/runnable@ForkJoinPool-5-worker-1
Summary
This blog post explains how to compile a Quarkus application leveraging virtual threads into a native executable.
First, make sure that you have a GraalVM installation supporting Java 21+.
Then, add the native
profile to the pom.xml
file and compile the application using the -Dnative
option.
Finally, run it as any other native executable!