Virtual Threads Explained - Sip of JavaBilly Korando on October 30, 2023
Virtual Threads, the long-awaited centerpiece of Project Loom, has been made a final feature in Java 21. So why do Virtual Threads have so many Java developers excited? Let’s take a look!
On the JVM, all code is executed on threads. Historically, threads in Java have been a relatively heavy-weight object as threads were tied to the underlying thread provided by the OS.
This wouldn’t represent a significant issue for applications that only need a few dozen threads. However, web applications that often follow a thread-per-request model could quickly use all available threads.
This wouldn’t necessarily be a problem if the threads were being highly utilized; however, the threads of many web applications often spend a considerable amount of time idling while waiting for a response from external services like a database or calling another web service.
This could lead to the under-desirable state of an application that has maxed out its thread allocation while still having low CPU utilization.
Project Loom aims to address this issue by splitting threads into two distinct concepts.
Platform Threads are instances of
java.lang.Thread and are a wrapper for the OS threads provided by the platform.
Virtual Threads extend
java.lang.Thread but run on top of Platform Threads and are not linked to underlying OS threads.
The JDK can schedule and unschedule virtual threads by watching for blocking operations, such as
BlockingQueue.take(), and listening for bytes to be received on a socket.
The scheduling of Virtual Threads is handled by default with a
java.util.concurrent.ForkJoinPool. It operates on a FIFO model and has a parallel capacity equivalent to the number of available Platform Threads, which itself is based on the number of available processors. These behaviors and values are configurable.
Maintaining Context and Debugging
Virtual Threads are not tied to a Platform Thread and are free to move between Platform Threads as needed. However, the context, thread-local values, stack trace, etc., stick with the Virtual Thread. Virtual Threads allow Java developers to get many benefits of reactive programming while maintaining the ease of writing and debugging provided by imperative programming.