Java 19 introduces virtual threads as an experimental feature to provide a more lightweight and efficient threading model compared to traditional Java threads. In this post, we’ll dive into what virtual threads are, why they were needed, and how they work under the hood.
Parallel vs Concurrent Execution
Before understanding virtual threads, let’s recap the difference between parallel and concurrent execution:
- Parallel execution is when multiple tasks literally execute at the same time, like on a multi-core CPU. Each task runs simultaneously on its own CPU core.
- Concurrent execution is when tasks appear to run simultaneously but are actually interleaved via techniques like context switching. This provides the illusion of concurrency on single-core CPUs.
Why Threads?
Threads help maximize hardware utilization for IO-bound tasks. Consider an example task that reads files, processes data, and writes output.
With a single thread, the CPU idles during IO operations like file read/write. But with multiple threads, while one thread waits on IO, another thread can utilize the CPU. So additional threads lead to higher CPU usage.
However, for CPU-bound tasks, too many threads actually lower performance due to context switching overheads. So the optimal number of threads depends on the type of work.
How Java Threads Work
Java uses native threads which have a one-to-one mapping to OS threads. The OS kernel manages the lifecycle of native threads.
The problem is, native threads have high overheads:
- Each thread requires 2-20 MB of dedicated stack memory.
- Creating and switching native threads needs expensive system calls.
These overheads limit how many threads can be created. For example, a 16 GB server may only support 800 threads.
But to fully utilize the CPU, you need a much higher thread count like 4500! Native threads become a scalability bottleneck.
Introducing Virtual Threads
These are lightweight threads managed by the JVM instead of the OS kernel. This removes the overheads of native threads.
Some key advantages of virtual threads:
- Extremely low memory footprint – just a few bytes per thread.
- No theoretical limit on the number of threads.
- No cost for thread creation/switching as no kernel involvement.
It use an M:N mapping to OS threads. Multiple virtual threads share a smaller pool of OS threads. This allows better utilization of available hardware resources.
Virtual threads support the same functionality as normal threads like synchronization and thread locals. They aim to provide a drop-in replacement for native threads but with much lower overheads.
Conclusion
Virtual threads in Java aim to optimize performance for highly concurrent workloads by providing extremely lightweight threading. This removes scalability bottlenecks and unlocks the ability to maximize hardware resource utilization.
The lightweight nature of virtual threads makes it feasible to have thousands or even millions of concurrent threads. This can help scale demanding server-side applications as well as simplify asynchronous programming models for clients.
These are still an experimental preview feature in Java 19, but they represent an exciting new direction for building highly concurrent systems with Java.
Let me know if you have any other questions about virtual threads in the comments!
Stay tuned for Video. 🙂
Share your thoughts