Introduction

The world of programming is constantly evolving, and with the release of Java 21, a groundbreaking concept has emerged – virtual threads.
In this article, we will delve into the world of virtual threads in java 21, exploring their significance in concurrent programming and how they have revolutionized the Java thread model.
From understanding the basics to examining real-world use cases, we will cover all aspects of virtual threads to provide you with a comprehensive understanding of this exciting new feature.

virtual threads in java 21

I. Understanding the Need for Virtual Threads in Java 21

As technology advances and applications become more complex, the need for efficient concurrent programming becomes increasingly critical.

The threads that we are familiar in java are instances of java.lang.Thread class.
These threads are also called Platform Threads.
A Platform Thread uses an OS thread to perform its task. It captures the OS thread till the task is completed.
Each platform thread is mapped one to one to an OS thread. This means that the number of platform threads are limited to the number of OS threads.
Now, the number of OS threads are heavy and are limited to the amount of available memory.
This is the reason that creating a platform thread is expensive and multiple platform threads slow down the application, leading to challenges in achieving optimal performance and resource utilization.

This is where virtual threads come into play.
Virtual threads offer a new approach to concurrency, allowing for lightweight and scalable execution that can handle massive workloads with ease.

II. The Basics of Virtual Threads

A. Definition and Concept of Virtual Threads

Virtual threads can be thought of as lightweight, user-space threads that are managed by the Java Virtual Machine (JVM).
Unlike traditional platform(or OS) threads, virtual threads are not tied to an OS thread for the entire task.
When a virtual thread needs to block for some I/O operation, it releases the OS thread.
This OS thread can then be used to perform task of some other thread.

Remember that a virtual thread is also an instance of java.lang.Thread class.

From Oracle docs,

Virtual threads are lightweight threads that reduce the effort of writing, maintaining, and debugging high-throughput concurrent applications.

Virtual threads should be used in high-throughput concurrent applications and where most of the tasks are in waiting state.
Remember that virtual threads are NOT faster than platform threads. Its just that they can be created in larger numbers and quickly as compared to platform threads.
And so, they provide higher throughput.

Virtual Thread Scheduling

Platform Threads are scheduled by the underlying OS while Virtual Threads are scheduled by JVM Scheduler.
When JVM schedules a virtual thread, it assigns a platform thread to this virtual thread. This is called mounting and the platform thread is called carrier.
When this virtual thread need to wait or block, the platform thread is released, called unmounting and the carrier(platform) thread is mounted to another virtual thread.

B. Differentiating Virtual Threads from Platform Threads

1. It is evident from the discussion till this point that Platform Thread captures an OS thread for its entire lifetime, even when it needs to wait or block for some I/O operation.
While, a virtual thread releases the OS thread when it is blocked.
So, a single OS thread might be processing the tasks of multiple virtual threads.

Virtual threads are suitable for running tasks are frequently blocked, such as I/O operations or synchronous network calls.
They aren’t intended for long-running CPU-intensive operations.

2. Virtual threads are always daemon threads while Platform threads can be configured to be daemon or non-daemon threads with setDaemon() method.

3. You cannot change the priority of a virtual thread with setPriority() method.

C. Benefits and Advantages of Virtual Threads

Virtual threads bring several advantages to the table.

  • Their lightweight nature allows for the creation of millions of threads without worrying about excessive resource consumption.
  • Virtual threads are highly scalable, meaning they can handle large workloads efficiently.
  • They offer improved isolation and thread safety, making concurrent programming more robust and reliable.

III. Creating Virtual Threads in Java 21

There are multiple ways to create a virtual thread in java 21.

A. Thread.ofVirtual()

Use static ofVirtual() method of java.lang.Thread class to create virtual threads and set various parameters such as thread priority and group.

Thread thread = Thread.ofVirtual().start(() -> System.out.println("Virtual thread"));
thread.join();

Below example shows how to set the name of virtual thread

Thread.Builder builder = Thread.ofVirtual().name("VThread");
Runnable task = () -> {
    System.out.println("Running virtual thread");
};
Thread t = builder.start(task);
System.out.println("Thread t name: " + t.getName());
t.join();

So, you see Thread.ofVirtual() returns Thread.Builder, which has methods to set the name of thread and run it by providing a task.

The JVM takes care of scheduling and execution, ensuring efficient utilization of system resources.

B. Thread.startVirtualThread()

Call startVirtualThread() method of Thread class passing it a Runnable object as argument.
This Runnable represents the task to be executed by the thread. Example,

Runnable task = () -> {
    System.out.println("Running virtual thread");
};
Thread.startVirtualThread(task);

startVirtualThread() is also a static method.

C. ThreadFactory

Use java.util.concurrent.factory.ThreadFactory to create new threads on demand.
To get an object of ThreadFactory, use factory() method as shown below.
Once we have a factory, we can use its newThread() method to create a new thread.

Runnable task = () -> {
    System.out.println("Running virtual thread");
};
ThreadFactory factory = Thread.ofVirtual().factory();
Thread thread = factory.newThread(task);
thread.start();

D. Running Virtual Threads with ExecutorService

ExecutorService also provides support for running virtual threads with newVirtualThreadPerTaskExecutor() method added in java 21 as shown below.

ExecutorService e = Executors.newVirtualThreadPerTaskExecutor();
Runnable task = () -> System.out.println("Running thread");
Future<?> future = e.submit(task);
try {
  future.get();
} catch (Exception e) {
  e.printStackTrace();
}

IV. Exploring Virtual Thread Features

A. Lightweight and Scalable Nature of Virtual Threads

One of the key features of virtual threads is their lightweight nature.
Unlike OS threads, which can consume a significant amount of resources, virtual threads have minimal overhead.
This allows for the creation of a large number of threads without worrying about running out of system resources.

Additionally, thanks to their scalable design, virtual threads can handle massive workloads without sacrificing performance.

B. Enhanced Resource Utilization with Virtual Threads

Virtual threads, being managed within the JVM, enable better resource utilization.
By reducing the reliance on OS threads, virtual threads can optimize scheduling and execution, resulting in more efficient use of CPU cycles and memory.
This leads to improved overall system performance and reduced resource contention.

C. Isolation and Thread Safety in Virtual Thread Paradigm

Concurrency brings with it the challenge of maintaining isolation and ensuring thread safety.
Virtual threads tackle this challenge head-on by providing improved isolation between threads.
The JVM’s scheduling mechanism helps prevent thread interference and data races, making concurrent programming more reliable and easier to reason about.

VI. Real-World Use Cases and Examples

A. Multicore and Parallel Processing Applications

With the increasing prevalence of multicore processors, virtual threads prove to be a powerful tool for developing highly parallelized applications.
By utilizing parallel and concurrent algorithms, developers can leverage virtual threads to execute tasks in parallel across multiple cores, maximizing performance and efficiency.

B. Asynchronous Programming and Event-Based Systems

Event-driven and asynchronous programming have become vital in modern application development.
Virtual threads provide a natural fit for these paradigms, allowing developers to handle multiple events concurrently and efficiently.
By using virtual threads, developers can create event-driven systems that are highly responsive and can handle a large number of concurrent events simultaneously.

C. Concurrent Data Structures and Synchronization

Concurrency is a fundamental aspect of many applications, especially those dealing with large datasets.
Virtual threads can greatly simplify the development of concurrent data structures by providing improved thread safety and isolation.
From concurrent collections to fine-grained synchronization, virtual threads offer a more intuitive and reliable approach to handling concurrent data access.

VII. Summary of Virtual Threads in Java 21

In summary, virtual threads in Java 21 offer a groundbreaking approach to concurrent programming.
By decoupling thread scheduling from the underlying operating system and leveraging the power of the JVM, virtual threads provide lightweight, scalable execution with enhanced resource utilization.
With their numerous benefits and real-world applications, virtual threads are set to reshape the programming landscape and empower developers to build high-performance, concurrent applications.

VIII. Frequently Asked Questions (FAQs)

A. What are Virtual Threads, and why are they important in Java 21?

Virtual threads are lightweight, user-space threads managed by the JVM. They are important in Java 21 as they bring significant performance gains, better resource management, and enhanced isolation and thread safety, making concurrent programming more efficient and robust.

B. How do Virtual Threads differ from traditional OS Threads?

Virtual threads differ from traditional OS threads in their implementation. While OS threads rely on the operating system for scheduling, virtual threads are managed entirely within the JVM.
This allows for lower overhead, improved control over execution, and better overall performance.

C. Are there any performance considerations when using Virtual Threads?

While virtual threads offer performance benefits, it is crucial to consider the potential overhead introduced by the JVM’s scheduling mechanism.
Evaluating this overhead and optimizing tasks and synchronization are key to achieving optimal performance with virtual threads.

D. What are the potential use cases for Virtual Threads in real-world applications?

Virtual threads find applications in multicore and parallel processing, asynchronous programming, and concurrent data structures.
They are particularly suited for highly parallelized applications, event-driven systems, and applications dealing with large datasets that require efficient concurrent access.

E. How can Java developers adapt to the Virtual Thread paradigm in Java 21?

To adapt to the virtual thread paradigm, Java developers should familiarize themselves with the updated thread model in Java 21 and learn the best practices for optimal virtual thread performance.
They should also explore real-world examples and use cases to gain a deeper understanding of virtual threads’ capabilities and potential in their applications.

Conclusion

Remember, virtual threads are more than just a buzzword – they represent a shift in how we approach concurrent programming in Java.
Embracing this paradigm opens up new possibilities for developers and enables the development of high-performance applications that can handle the demands of the modern world.

So why wait? Dive into the world of virtual threads in Java 21 and unlock the true potential of concurrent programming!