thecodex.expert · The Codex Family of Knowledge
Java

Virtual Threads

A traditional Java platform thread is genuinely expensive — a few thousand of them can exhaust a server. A virtual thread is so lightweight that a single application can run millions.

Java 21 LTS Finalized in Java 21 Last verified:
Canonical Definition

Traditional Java threads (now called "platform threads") map one-to-one onto operating system threads, which are genuinely expensive to create and hold in memory — a server can typically sustain only a few thousand at once. Virtual threads, finalized in Java 21 after years of development under Project Loom, are managed entirely by the JVM and are dramatically cheaper: a single application can run millions of them concurrently. Critically, virtual threads use the exact same Thread API Java code has always used — existing thread-per-request code often gains this benefit with minimal changes, rather than requiring a rewrite around a new async programming model.

Creating a virtual thread

Starting 100,000 platform threads simultaneously would exhaust most machines' memory and OS thread limits; the identical code with virtual threads runs comfortably, since each one is dramatically cheaper.

JavaVirtualThreadBasics.java
Thread thread = Thread.ofVirtual().start(() -> {
    System.out.println("Running on a virtual thread");
});
thread.join();

// running 100,000 concurrent tasks — impractical with platform threads, fine with virtual ones
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 100_000; i++) {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return null;
        });
    }
}

Why this matters: I/O-bound workloads specifically

Virtual threads shine specifically for I/O-bound work — a web server handling thousands of concurrent requests that each spend most of their time waiting on a database or network call. The JVM automatically "parks" a virtual thread during a blocking I/O call, freeing the underlying platform thread (called a "carrier thread") to run other virtual threads in the meantime, then resumes it when the I/O completes — all transparent to the code, which still just calls a normal blocking method.

Existing thread-per-request code, mostly unchanged

Because virtual threads implement the same java.lang.Thread API, code written in the traditional "one thread handles one request, blocking calls are fine" style — rather than a reactive or async style — often gains this scalability improvement by switching the thread-creation mechanism, without restructuring the application's actual logic around callbacks or reactive streams.

Sources

1
Oracle. Virtual Threads, docs.oracle.com/en/java/javase/25/core/virtual-threads.html, and JEP 444.