advancedModern Java & Architecture

How do virtual threads work internally, end to end?

A virtual thread is a lightweight thread managed entirely by the JVM rather than by the operating system. Each one is represented as a heap object with an elastic stack that starts out extremely small, around 200 bytes, and grows only as needed. The JVM's own scheduler, built on a ForkJoinPool, multiplexes potentially huge numbers of virtual threads onto a small, fixed pool of real operating-system "carrier" threads, whose count defaults to the number of available CPU cores. When a virtual thread makes a blocking call recognized by the JDK, such as a socket read, file I/O, or sleep, the JVM unmounts it: it saves the virtual thread's stack into the heap and immediately frees up the carrier thread to go run some other virtual thread. Once the blocking operation actually completes, the original virtual thread is remounted onto whichever carrier thread is available at that moment and resumes execution. This is why a million virtual threads only costs roughly gigabytes of heap for their stacks, rather than the terabyte of OS-level stack space a million platform threads would require. From the programmer's point of view, the code is written in an ordinary, sequential, blocking style, while the JVM transparently handles the actual asynchronous scheduling underneath.

Ready to master this question?

Generate a complete walkthrough — background, the full answer in plain language, a working code example explained line by line, a real-world scenario, common mistakes, and how this same question gets asked in different ways.

Sign in to generate a response

Next Step

Continue to What is Structured Concurrency, and what problem does it solve?← Back to all Java Concurrency & Multithreading questions