Java Concurrency: From Threads to Virtual Threads in Java 21
2 years ago
•22 min read
95
14

Java Concurrency: From Threads to Virtual Threads in Java 21
Concurrency has always been one of Java's strongest suits, but it's also been one of the most complex. With the release of Java 21, a new era has begun with the introduction of Virtual Threads (Project Loom).
The Problem with Platform Threads
Traditionally, each java.lang.Thread was a wrapper around an OS thread. These are expensive:
- They consume significant memory (about 1MB per thread).
- Context switching between OS threads is slow.
- You can't realistically have millions of them.
This led to the rise of reactive programming, which is powerful but notoriously difficult to write, debug, and maintain.
Enter Virtual Threads
Virtual Threads are lightweight threads that are not tied to OS threads. They are managed by the Java runtime.
- Extremely Lightweight: You can spawn millions of them without breaking a sweat.
- Blocking is Free: When a Virtual Thread performs a blocking I/O operation, the runtime simply parks it and uses the underlying OS thread for something else.
- Simple Programming Model: You can go back to writing simple, synchronous-looking code that scales like reactive code.
How to Use Virtual Threads
Spawning a Virtual Thread is as simple as:
Thread.ofVirtual().start(() -> {
System.out.println("Hello from a Virtual Thread!");
});
Or using an Executor:
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
} // executor.close() is called automatically, waiting for all tasks
When to Use Virtual Threads?
Virtual Threads are perfect for I/O bound tasks (e.g., handling HTTP requests, database calls). They are not a magic bullet for CPU-bound tasks (e.g., video encoding or complex math), as those still need actual CPU cores.
Conclusion
Virtual Threads are a game-changer. They bring back simplicity to high-performance Java development, allowing developers to focus on business logic rather than complex asynchronous plumbing.