Image of gears and charts on a dark background
January 10, 2024

Java Basics: What are Virtual Threads?

Java Updates

If you were paying attention to the Java 21 release, you may have noticed that virtual threads are now a permanent JDK feature. Perhaps you’re applauding long-term support for a feature you’ve played around with since Java 19. But if you’re not sure what virtual threads are or what they mean for your Java development practice, rest assured 


Back to top

What Are Virtual Threads?

Virtual threads are lightweight threads that simplify writing and maintaining concurrent applications with high compute requirements.   

Traditional platform threads are very heavy, i.e., they use a significant amount of compute resources, and are bound 1:1 to the OS thread, which means that execution time of the threads is dependent on the CPU’s execution time.  

Each of these threads would end up utilizing as much as 10 GB of memory; this adds up quickly depending on any level of complexity implemented in your application. These threads were designated to use a single thread with every request. While traditional threads provide a level of simplicity for developing applications, the lack of flexibility often resulted in large applications being negatively impacted by the amount of requests made by the code. 

Virtual threads, on the other hand, move the responsibility of scheduling threads from the OS to the JVM (Java Virtual Machine), effectively introducing an abstraction layer between the OS and the application.  

Virtual threads were created with a few distinct purposes in mind. First, they enable Java developers to write server applications using a simple thread-per-request style. Second, virtual threads enable Java developers to utilize hardware to the fullest extent possible by eliminating the OS as the limiting factor to performance.  

Example of Virtual Thread 

Runnable fn = () -> { // code};  

Thread thread = Thread.ofVirtual(fn) .start(); 

Thread thread = Thread.startVirtualThread(() -> { //code }); 
Back to top

How Virtual Threads Became a Permanent JDK Feature

Virtual threads were first proposed as a preview feature in Java 19.At the time, they had been in development in Project Loom for several years before their introduction into the JDK with JEP 425. Virtual threads are a prerequisite for structured concurrency.  

In Java 20, virtual threads appeared as a preview feature for a second time with JEP 436. Java developer feedback helped to finalize the feature for Java 21, including: 

  • Support for thread-local variables 
  • Default monitoring of threads created with the Thread.Builder API 

With those improvements now implemented, virtual threads became a permanent JDK feature with Java 21.  

Watch this recorded webinar to discover more of the hidden gems of Java 21. 

Watch now   

Back to top

What’s the Purpose of Virtual Threads?

Virtual threads were created with a few distinct purposes in mind. First, they enable Java developers to write server applications using a simple thread-per-request style. Since server applications handle user requests independent of one another, it makes sense for each request to be assigned a dedicated thread for its duration.  

Virtual threads also enable simple troubleshooting, debugging and profiling using existing JDK tools.  

By enabling existing code that uses the java.lang.Thread API, virtual threads can be implemented with minimal change, which was a primary stated goal in JEP 444 

[H3] Stated Non-Goals of Virtual Threads 

It’s also important to note OpenJDK’s stated non-goals for JEP 444. Virtual threads are not intended to change the basic concurrency model of Java, nor are they intended to replace traditional threads.  

They’re also not intended to serve as a new parallelism construct for either the Java language or Java libraries; Stream API remains a more effective method to process large data sets in parallel.  

📚 Further Reading: Learn more about the hidden gems in Java 21.   

Mitigating Performance Issues With Virtual Threads 

Virtual threads were developed to overcome performance limitations with traditional threads and enable Java developers to maximize hardware performance. One of the primary goals of virtual threads was to make threads cheaper so that developers can employ more of them without incurring performance limitations. 

Perhaps the biggest advantage of these new additions is that there is very little difference in the code for virtual threads when compared to other non-virtual thread options. 

If your Java application has CPU-bound tasks, such as running a video game, virtual threads may not result in performance improvements.  

Virtual Thread Dos and Don’ts

While Java developers are still experimenting in how to best implement virtual threads in their workflows, there are a few best practices to keep in mind.  

  • Start a new virtual thread for every task 
  • Virtual threads should not be pooled 
  • Most virtual threads will have shallow call stacks and thus be short-lived 
Back to top

Final Thoughts

By implementing virtual threads, Java developers can overcome a limitation of traditional threads by moving the scheduling responsibility from the OS to the application server. While virtual threads are not a new parallelism construct for Java, they are a unique solution for specific circumstances.  

Looking for more ways to increase efficiency in your Java development practice? Consider JRebel. By eliminating redeploys, you can visualize code changes instantly while maintaining application state.  

Want to see what you can accomplish with 10% more Java development time? Start your 14-day free trial of JRebel 

Try free

Back to top