DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Taming the Virtual Threads: Embracing Concurrency With Pitfall Avoidance
  • Micro Frontends for Quarkus Microservices
  • Microservices With Apache Camel and Quarkus (Part 4)
  • Microservices With Apache Camel and Quarkus

Trending

  • Can Claude Skills Replace Playwright Agents? A Practical View for QA Engineers
  • Content Lakes: Harness Unstructured Data for Enterprise AI Readiness
  • Detecting Bugs and Vulnerabilities in Java With SonarQube
  • No More Cheap Claude: 4 First Principles of Token Economics in 2026
  1. DZone
  2. Coding
  3. Java
  4. Quarkus 3: The Future of Java Microservices With Virtual Threads and Beyond

Quarkus 3: The Future of Java Microservices With Virtual Threads and Beyond

Learn how Quarkus integrates the virtual thread for Java developers to run blocking applications with a single @RunOnVirtualThread annotation.

By 
Daniel Oh user avatar
Daniel Oh
DZone Core CORE ·
Dec. 01, 23 · Tutorial
Likes (9)
Comment
Save
Tweet
Share
20.8K Views

Join the DZone community and get the full member experience.

Join For Free

Over the past four years, developers have harnessed the power of Quarkus, experiencing its transformative capabilities in evolving Java microservices from local development to cloud deployments. As we stand on the brink of a new era, Quarkus 3 beckons with a promise of even more enhanced features, elevating developer experience, performance, scalability, and seamless cloud integration.

In this enlightening journey, let’s delve into the heart of Quarkus 3's integration with virtual threads (Project Loom). You will learn how Quarkus enables you to simplify the creation of asynchronous concurrent applications, leveraging virtual threads for unparalleled scalability while ensuring efficient memory usage and peak performance. 

Journey of Java Threads

You might have some experience with various types of Java threads if you have implemented Java applications for years. Let me remind you real quick how Java threads have been evolving over the last decades. Java threads have undergone significant advancements since their introduction in Java 1.0. The initial focus was on establishing fundamental concurrency mechanisms, including thread management, thread priorities, thread synchronization, and thread communication. As Java matured, it introduced atomic classes, concurrent collections, the ExecutorService framework, and the Lock and Condition interfaces, providing more sophisticated and efficient concurrency tools.

Java 8 marked a turning point with the introduction of functional interfaces, lambda expressions, and the CompletableFuture API, enabling a more concise and expressive approach to asynchronous programming. Additionally, the Reactive Streams API standardized asynchronous stream processing and Project Loom introduced virtual threads, offering lightweight threads and improved concurrency support.

Java 19 further enhanced concurrency features with structured concurrency constructs, such as Flow and WorkStealing, providing more structured and composable concurrency patterns. These advancements have significantly strengthened Java's concurrency capabilities, making it easier to develop scalable and performant concurrent applications. Java threads continue to evolve, with ongoing research and development focused on improving performance, scalability, and developer productivity in concurrent programming.

Virtual threads, generally available (GA) in Java 21, are a revolutionary concurrency feature that addresses the limitations of traditional operating system (OS) threads. OS threads are heavyweight, limited in scalability, and complex to manage, posing challenges for developing scalable and performant concurrent applications.

Virtual threads also offer several benefits, such as being a lightweight and efficient alternative, consuming less memory, reducing context-switching overhead, and supporting concurrent tasks. They simplify thread management, improve performance, and enhance scalability, paving the way for new concurrency paradigms and enabling more efficient serverless computing and microservices architectures. Virtual threads represent a significant advancement in Java concurrency, poised to shape the future of concurrent programming.

Getting Started With Virtual Threads

In general, you need to create a virtual thread using Thread.Builder directly in your Java project using JDK 21. For example, the following code snippet showcases how developers can create a new virtual thread and print a message to the console from the virtual thread. The Thread.ofVirtual() method creates a new virtual thread builder, and the name() method sets the name of the virtual thread to "virtual-thread". Then, the start() method starts the virtual thread and executes the provided Runnable lambda expression, which prints a message to the console. Lastly, the join() method waits for the virtual thread to finish executing before continuing. The System.out.println() statement in the main thread prints a message to the console after the virtual thread has finished executing.

Java
 
public class MyVirtualThread {

    public static void main(String[] args) throws InterruptedException {

        // Create a new virtual thread using Thread.Builder
        Thread thread = Thread
                .ofVirtual()
                .name("my-vt")
                .start(() -> {
                    System.out.println("Hello from virtual thread!");
                });

        // Wait for the virtual thread to finish executing
        thread.join();
        System.out.println("Main thread completed.");

    }

}


Alternatively, you can implement the ThreadFactory interface to start a new virtual thread in your Java project with JDK 21. The following code snippet showcases how developers can define a VirtualThreadFactory class that implements the ThreadFactory interface. The newThread() method of this class creates a new virtual thread using the Thread.ofVirtual() method. The name() method of the Builder object is used to set the name of the thread and the factory() method is used to set the ThreadFactory object.

Java
 
// Implement a ThreadFactory to start a new virtual thread
public class VirtualThreadFactory implements ThreadFactory {

    private final String namePrefix;

    public VirtualThreadFactory(String namePrefix) {
        this.namePrefix = namePrefix;
    }

    @Override
    public Thread newThread(Runnable r) {

        return Thread.ofVirtual()
                .name(namePrefix + "-" + r.hashCode())
                .factory(this)
                .build();
    }

}


You might feel it will get more complex when you try to run your actual methods or classes on top of the virtual threads. Luckily, Quarkus enables you to skip the learning curve and execute the existing blocking services on the virtual threads quickly and efficiently. Let’s dive into it.

Quarkus Way to the Virtual Thread

You just need to keep reminding yourself of two things to run an application on virtual threads. 

  •  Implement blocking services rather than reactive (or non-blocking) services based on JDK 21.
  • Use @RunOnVirtualThread annotation on top of a method or a class that you want.

Here is a code snippet of how Quarkus allows you to run the process() method on a virtual thread.

Java
 
@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @RunOnVirtualThread
    public String hello() {
    
        Log.info(Thread.currentThread());
        return "Quarkus 3: The Future of Java Microservices with Virtual Threads and Beyond";
    
    }

}


You can start the Quarkus Dev mode (Live coding) to verify the above sample application. Then, invoke the REST endpoint using the curl command. 

Shell
 
$ curl http://localhost:8080/hello


The output should look like this.

Shell
 
Quarkus 3: The Future of Java Microservices with Virtual Threads and Beyond


When you take a look at the terminal, you see that Quarkus dev mode is running. You can see that a virtual thread is created to run this application. 

Shell
 
(quarkus-virtual-thread-0) VirtualThread[#123,quarkus-virtual-thread-0]/runnable@ForkJoinPool-1-worker-1


Try to invoke the endpoint a few more times, and the logs in the terminal should look like this.

You learned how Quarkus integrates the virtual thread for Java developers to run blocking applications with a single @RunOnVirtualThread annotation. You should be aware that this annotation is not a silver bullet for all use cases. In the next article, I’ll introduce pitfalls, limitations, and performance test results against reactive applications.

Java Development Kit Quarkus Java (programming language) microservice

Opinions expressed by DZone contributors are their own.

Related

  • Taming the Virtual Threads: Embracing Concurrency With Pitfall Avoidance
  • Micro Frontends for Quarkus Microservices
  • Microservices With Apache Camel and Quarkus (Part 4)
  • Microservices With Apache Camel and Quarkus

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook