Introducing virtual threads 4 – Concurrency – Virtual Threads, Structured Concurrency
Printing a thread (toString())
If we print a virtual thread (calling the toString() method) then the output will be something as follows:
VirtualThread[#22]/runnable@ForkJoinPool-1-worker-1
VirtualThread[#26,vt-0]/runnable@ForkJoinPool-1-worker-1
In a nutshell, this output can be interpreted as follows: VirtualThread[#22] indicates that this is a virtual thread that contains the thread identifier (#22) with no name (in the case of VirtualThread[#26,vt-0], the id is #26 and the name is vt-0). Then, we have the runnable text which indicates the state of the virtual thread (runnable means that the virtual thread is running). Next, we have the carrier thread of the virtual thread which is a platform thread: ForkJoinPool-1-worker-1 contains the platform thread name (worker-1) of the default ForkJoinPool (ForkJoinPool-1).
How many virtual threads we can start
Finally, let’s run a code that allows us to see how many virtual threads we can create and start:
AtomicLong counterOSThreads = new AtomicLong();
while (true) {
Thread.startVirtualThread(() -> {
long currentOSThreadNr
= counterOSThreads.incrementAndGet();
System.out.println(“Virtual thread: “
+ currentOSThreadNr);
LockSupport.park();
});
}
On my machine, this code started to slow down after around 14,000,000 virtual threads. It continues to run slowly while memory gets available (Garbage Collector in action) but didn’t crush. So, a massive throughput!
Backward compatibility
Virtual threads are compatible with:
Synchronized blocks
Thread-local variables
Thread and currentThread()
Thread interruption (InterruptedException)
Basically, virtual threads work out of the box once you update to at least JDK 19. They heavily sustain a clean, readable, and more structured code being the bricks behind the structured concurrency paradigm.
Avoiding fake conclusions (potentially myths)
Virtual threads are faster than platform threads (FAKE!): Virtual threads can be quite many but they are not faster than classical (platform) threads. They don’t boost in-memory computational capabilities (for that we have the parallel streams). Don’t conclude that virtual threads do some magic that makes them faster or more optimal for solving a task. So, virtual threads can seriously improve throughput (since millions of them can wait for jobs) but they cannot improve latency. However, virtual threads can be launched much faster than platform threads (a virtual thread has a creating time in the order of the µs and needs a space in the order of kB).Virtual threads should be pooled (FAKE!): Virutal threads should not be part of any thread pool and should never be pooled.Virtual threads are expensive (FAKE!): Virtual threads are not for free (nothing is for free) but they are cheaper to create, block, and destroy than platform threads. A virtual thread is 1000x cheaper than a platform thread.Virtual threads can release a task (FAKE!): This is not true! A virtual thread takes a task and should return a result or gets interrupted. It cannot release the task.Blocking a virtual thread blocks its carrier thread (FAKE!): Blocking a virtual thread doesn’t block its carrier thread. The carrier thread can server other virtual threads.