Java Virtual Threads
In this page:
Thread.ofVirtual().start(runnable);
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(task);
}
What are Virtual Threads?
Virtual threads, finalized in Java 21 as part of Project Loom, are lightweight threads managed entirely by the JVM rather than mapped one-to-one to an operating system thread, allowing a program to run huge numbers of them cheaply.
Example: What are Virtual Threads?
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread vt = Thread.ofVirtual().start(() -> System.out.println("Running on a virtual thread")); // JVM-managed, lightweight
vt.join();
}
}
Login to try C/C++/Java/PHP code in the editor
Creating a Virtual Thread
Virtual threads are created using the new Thread.ofVirtual() builder or the shortcut Thread.startVirtualThread, both of which behave like a normal Thread from the calling code's perspective but carry far less overhead.
Example: Creating a Virtual Thread
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t1 = Thread.ofVirtual().start(() -> System.out.println("via ofVirtual()"));
Thread t2 = Thread.startVirtualThread(() -> System.out.println("via startVirtualThread")); // shortcut
t1.join(); t2.join();
}
}
Login to try C/C++/Java/PHP code in the editor
Virtual Threads vs Platform Threads
A platform thread, created with new Thread(), maps directly to a limited operating system thread, while a virtual thread is scheduled by the JVM onto a small pool of carrier threads, letting millions of virtual threads exist where only thousands of platform threads could.
Example: Virtual Threads vs Platform Threads
// Define the class Main
public class Main {
// Program entry point: the JVM starts running here
public static void main(String[] args) throws InterruptedException {
// Create a new Thread object and store it in platform
Thread platform = new Thread(() -> System.out.println("Platform thread: " + Thread.currentThread()));
Thread virtual = Thread.ofVirtual().unstarted(() -> System.out.println("Virtual thread: " + Thread.currentThread()));
// Start the thread; it runs in parallel with this code
platform.start(); platform.join();
// Start the thread; it runs in parallel with this code
virtual.start(); virtual.join();
}
}
Login to try C/C++/Java/PHP code in the editor
Virtual Threads with ExecutorService
Executors.newVirtualThreadPerTaskExecutor() creates a new virtual thread for every task submitted to it, rather than reusing a fixed-size pool, which works well because virtual threads are cheap enough to create one per task.
Example: Virtual Threads with ExecutorService
// Import java.util.concurrent.* so it can be used by its short name
import java.util.concurrent.*;
// Define the class Main
public class Main {
// Program entry point: the JVM starts running here
public static void main(String[] args) throws Exception {
// Try code that might throw an exception
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> System.out.println("New virtual thread per task"));
}
}
}
Login to try C/C++/Java/PHP code in the editor
When to Use Virtual Threads
Virtual threads are ideal for high-throughput, I/O-bound workloads like handling many concurrent network requests or database calls, since blocking a virtual thread is inexpensive, but they offer little benefit for CPU-bound computation, which is limited by processor cores instead of thread count.
Example: When to Use Virtual Threads
// Define the class Main
public class Main {
// Program entry point: the JVM starts running here
public static void main(String[] args) {
// Print a line to the console
System.out.println("Good fit: many I/O-bound network/database calls");
// Print a line to the console
System.out.println("Poor fit: CPU-bound computation, limited by processor cores");
}
}
Login to try C/C++/Java/PHP code in the editor
- Expecting the program to wait for virtual threads, when they are daemon threads, so
maincan exit first unless you calljoin(). - Putting virtual threads in a fixed-size pool, when they are cheap and meant to be created one per task.
- Using virtual threads for CPU-heavy work, when they help with blocking I/O and give no speed-up for tasks that keep the CPU busy.
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first: