Virtual Threads Shift System Resource Management from Application Code to the JVM: A First Look at Java 21
One of the most impactful updates introduced in Java 19 was the advent of virtual threads, a key feature of Project Loom. These virtual threads, now officially integrated into the Java Virtual Machine (JVM) since Java 20, represent a significant shift in how Java handles concurrency and resource management.
Virtual threads introduce a new abstraction layer between operating system processes and application-level concurrency. Unlike traditional threads, which are mapped directly onto operating system processes and require the application to manage resource allocation, virtual threads allow the JVM to handle these responsibilities. This means that while applications create and manage virtual threads, it is the JVM that coordinates the allocation and deallocation of system resources. This architecture contrasts sharply with the conventional model, where each thread corresponds directly to an OS thread and the application is responsible for provisioning these resources.
The operational mechanics of virtual threads can be likened to goroutines in the Go language. When a virtual thread is not actively performing work, it is parked—essentially idle and waiting for new tasks. This idling is a common scenario in many server applications, where threads are often assigned to handle requests and then remain idle while waiting for further events or responses from external sources. The JVM optimizes the use of compute resources by allocating them only when virtual threads are actively engaged, improving efficiency and scalability.
In essence, virtual threads represent an advanced form of thread pooling. Traditional Java threads suffer from limitations in scalability due to the one-to-one relationship between OS threads and application threads. When a server is idling on a request, it consumes an OS thread that is also idle, constraining the server’s scalability. As explained by Nicolai Parlog, “Operating systems can’t increase the efficiency of platform threads, but the JDK will make better use of them by severing the one-to-one relationship between its threads and OS threads.” By decoupling the application’s threads from the underlying OS threads, virtual threads help to alleviate these limitations and enhance overall performance.
The introduction of virtual threads marks a notable evolution in Java’s concurrency model, allowing for more efficient handling of large numbers of concurrent tasks. This shift not only simplifies concurrency management for developers but also significantly boosts the scalability of Java applications. With virtual threads, developers can achieve higher levels of concurrency without the overhead traditionally associated with managing a large number of OS threads, making it easier to build robust and scalable applications.
As virtual threads continue to gain traction, their impact on Java development is expected to be profound. By improving resource management and scalability, virtual threads offer a promising advancement in the evolution of Java, addressing long-standing challenges in concurrency and paving the way for more efficient and scalable applications.