With Java 21, Virtual Threads are no longer just an experimental idea β they are here to revolutionize how we handle concurrency in Java. Lets see how Virtual Threads in Java 21 can be a game changer for concurrency.

π What Is Concurrency in Java?
Concurrency means doing multiple things at once.
In Java:
- This is done using threads β units of work that can run independently.
- Traditionally, Java has relied on platform threads, which are managed by the Operating System (OS).
A typical server application uses threads to:
- Handle each HTTP request
- Call external APIs or databases
- Process background jobs
π© The Pain Points of Platform Threads
Platform threads have been around for years, but they come with some big limitations:
1. π¦ Heavyweight
- Each thread uses around 1MB of memory stack.
- Systems can’t handle more than a few thousand threads efficiently.
2. β Blocking Wastes Resources
- If a thread waits (e.g., on I/O or a DB call), it just sits there doing nothing but still consuming resources.
3. π₯ Thread Starvation
- You can run out of threads under high load.
- This leads to latency spikes, dropped requests, or crashes.
π‘ Enter: Virtual Threads in Java 21
β What Are Virtual Threads?
- Introduced as a preview feature in Java 21 under Project Loom
- A virtual thread is not backed by an OS thread directly.
- Managed by the Java Virtual Machine (JVM)
- Scheduled in user space, not by the OS
π Key Properties:
Feature | Virtual Threads |
---|---|
Lightweight | Only needs a few KB of memory |
Cheap to create | You can spawn millions of them |
Suspendable | Can pause when waiting (I/O) without blocking a platform thread |
Fully interoperable | Works with existing Java APIs (Thread, Executor) |
π§ How to Use Virtual Threads in Java
π§΅ Option 1: Launching a Virtual Thread
1 2 3 4 5 6 |
Thread.startVirtualThread(() -> { System.out.println("Running in a virtual thread!"); }); |
π§΅ Option 2: Using Virtual Thread Executor
1 2 3 4 5 6 7 8 9 10 |
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); executor.submit(() -> { // Your background task here System.out.println("Task running in virtual thread"); }); executor.shutdown(); |
β No new APIs to learn β it works just like regular threads!
π§ͺ Sample Program β Scaling to 100,000 Threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); for (int i = 0; i < 100000; i++) { executor.submit(() -> { try { Thread.sleep(1000); // Simulate delay System.out.println("Task completed by: " + Thread.currentThread()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } executor.shutdown(); |
π₯ This would crash with platform threads β but runs smoothly with virtual threads!
π How It Works Internally
- Virtual threads are mounted on platform threads only when running.
- If they hit a blocking operation (like sleep or I/O), they are unmounted.
- Other virtual threads can reuse the same platform thread.
This makes virtual threads non-blocking, efficient, and scalable.
π Comparison: Platform Threads vs Virtual Threads
Feature | Platform Threads | Virtual Threads |
---|---|---|
Memory Usage | ~1MB | ~Few KB |
Managed By | OS | JVM |
Number of Threads | Thousands | Millions |
Blocking Behavior | Blocks OS Thread | Does not block |
Startup Time | High | Near-instant |
Use Case | Parallelism | Concurrency (I/O-heavy) |
π― Best Use Cases for Virtual Threads
- π High-concurrency servers (e.g., REST APIs, chat apps)
- π Microservices making lots of remote calls
- π§° Task schedulers and job queues
- ποΈ Applications interacting with databases or external APIs
β οΈ Limitations and Considerations
- π¬ Still a preview feature in Java 21 (enable with
--enable-preview
) - π§ͺ Some blocking APIs (like native I/O) may not yet be optimized for virtual threads
- π§ Debugging tools and thread-local usage may behave differently
π οΈ How to Compile and Run with Virtual Threads
Since itβs a preview feature:
1 2 3 4 |
javac --enable-preview --release 21 VirtualThreadDemo.java java --enable-preview VirtualThreadDemo |
π§΅ Virtual Threads vs Reactive Programming
Feature | Virtual Threads | Reactive (e.g., Project Reactor) |
---|---|---|
Complexity | Very low (just use Thread ) | High (requires learning reactive APIs) |
Code Style | Imperative, familiar | Declarative, callback-based |
Debuggable | Easy to debug | Complex call stacks |
Ecosystem Support | Works with existing code | Requires reactive-aware libs |
π Virtual threads allow traditional blocking-style code with non-blocking performance.
π§Ύ Final Thoughts
π With Virtual Threads, Java makes concurrency simpler and scalable β no need for complex thread pools or callback chains. You write code just like you always have, and the JVM handles the efficiency for you.
Java 21 + Virtual Threads = Concurrency for Humans
Reference : Virtual Threads