Java Thread
First let's talk about the normal Java thread. Before we proceed further we have a new name for the normal Java thread and the name is Platform Thread. Now onward we will address normal Java thread as platform thread.
So why do we require a 'virtual thread'?
As we already know that Java platform thread is expensive and it runs on OS thread. It means whenever platform threads need to wait it blocks the precious OS thread. Consequently, we are not able to utilise the OS thread at optimum level and therefore, we are wasting it when platform threads wait for some tasks.
So, we require a thread which is good at waiting and at the same time can scale easily without eating-up the computer resources for unnecessary tasks like context switching. Virtual thread will not give us any significant or any advantage over platform thread.
As the virtual thread is good at waiting. So the ideal usage of the virtual thread will be when application is executing the IO operations like a database or other third party service calls, etc. During this IO operations virtual thread will wait for the IO operations to get complete without blocking the OS thread once the IO operation is done it will continue the rest of the task execution.
Now what is a 'virtual thread'?
What is a 'continuation' now?
Now about continuation, it is in other words delimited continuation and also sometimes is called coroutine (continuation + routine).Key properties of coroutine
- Can be suspended and resumed at anytime.
- It is a data structure that represents the process state and call stack trace.
- Can yield / give control to other coroutines.
- It must have isDone() method which tell us the execution is done or not, yield() method to suspend the current continuations unto the given scope and run() method to mounts and runs the continuation body. If suspended, continues it from the last suspend point.
We will understand the continuation / coroutine using an example.
How to create a virtual thread?
Terminologies we will be using in virtual thread
- JDK assigning a virtual thread to platform thread is called MOUNTING.
- JDK unassigned a virtual thread to platform thread is called UNMOUNTING.
- The platform thread which is running the virtual thread is called its CARRIER THREAD.
- Due to some reason both virtual and platform thread got blocked this is called PINNING of Operating System (OS) thread.
How does a 'virtual thread' work?
JDK creates a ForkJoinPool executor.
JDK then creates a continuation object.
Finally, on start() method invocation on virtual thread will schedule the execution.
- Assign the virtual thread to a carrier thread.
- Inherit the ExtendLocal bindings for the given carrier thread.
- Submit the task to the scheduler.
Example to understand virtual thread scheduler
VirtualThread[#21]/runnable@ForkJoinPool-1-worker-1 ==> Started the task this virtual thread
after came back from sleep
VirtualThread[#21]/runnable@ForkJoinPool-1-worker-2 ==> but the same task was completed by other virtual thread
Let's put scaling to the test for virtual thread
Statistic of Platform Thread |
Statistic of Virtual Thread |
- In case of virtual thread heap memory usage is more that platform thread. It is because when virtual thread is getting blocked it put its continuation object into heap memory.
- [virtual thread heap memory usage > platform thread heap memory usage]
- Only one extra class get loaded for virtual thread.
- [# of classes loaded in virtual thread > # of classes loaded in platform thread]
- More than three thousand platform threads got generated and processed whereas only twenty nine threads in case of virtual threads. As virtual threads are running on ForkJoinPool scheduler it does not required so many platform threads to get the execution completed.
- [# of platform threads > # of virtual thread's manager]
- Platform threads consumed CPU consistently than virtual threads.
Pinning
What are those reasons for pinning?
Reason for pinning |
During native call, monitor held (wait, notify, notifyAll) and in critical section execution (synchronized block execution) virtual thread could block the platform thread.
Pinning example |
Some of the best practice to follow for virtual thread
- Don't pool the virtual thread object.
- Revisit synchronized code for better scalability.
- Don't use TheadLocal rather user extend-local variables.