Thread Pools and ThreadPoolExecutor
Thread creation takes some time to create a thread. With thread pool we can save thread creation time by also reusing
the thread.
We can have control over our thread with thread pool.
When context switching happen, the CPU goes into idle state. So with more context switching the CPU will be idle for
long time.
Thread pool executer will have certain number of tasks, let’s assume 11 task and thread pool min size(core pool size) is
3, so we will have 3 threads, and the queue size is 5.
So, when all task comes to the thread pool, it will get assigned to either thread or the queue, so, task1->thread1, task2-
>thread2, task3->thread. Now, all the thread are busy, but we have other task coming, so we will put them in queue (size
of 5)->task4, task5, task6, task7, task8.
Now the queue is also full, but we have other tasks coming in the thread pool, so then the thread pool will check what is
the maximum number of thread size allocated(eg: size 5), then it will take tasks and assign it to the thread which will get
created by checking maximum size, when the thread and queue is full. So, task9->thread4, task10->thread5.
Now, we have task11 left, but all the min and max capacity thread is busy and also queue is full, in that case, it will reject
the task11.
Core pool size (min pool size) is sufficient to fulfil most of the request, and if any peak is coming then we have queue to
put that request in line.
Future, CompletableFuture and Callable – Follow up of thread pool executer
Currently, there is no way main() can know the stats of the thread1, as it is not holding any reference to it.
That’s when Future comes into the picture. Future helps in knowing the status of the thread, that is running in async
mode, by some other thread.
Submit is of future type, we can create a object of future type and store the reference there.
With get(), we are blocking the caller, till the time task is completed execution and then retrieve the result of the task.
This above example have 3 use case, all three are the variant of submit().
1)submit(Runnable)
2)submit(Runnable , T)
3)submit(callback <t>)
Java - Fork/Join Pool, Single, Fixed, CachedPool
Executer provide factory methods which we can use to create thread pool executer.
Present in [Link] package
A big task has to be divided into subtask using fork, and then those subtask will have their own subtask using fork only,
and then one subtask will call join or we can call join, where it will wait for all other subtask to get finished, and then it
will ultimately return the result.
Purpose: more parellism.
If subtask will return value then use Recursive Task, other time when sub task do not return anything then use Recursive
Action.
Java : ScheduledThreadPoolExecutor
ShutDownNow will not even wait for the thread to complete the execution, it will interrupt the thread execution and
terminate it.
Java: VirtualThreads and ThreadLocal
Each thread have a threadLocal variable, that store certain data.
Suppose we have, 10 thread and we do start those thread, by [Link](), the JVM will create 10 platform thread(normal
thread) and each platform thread will have OS thread to it.
JVM provide a wrapper for the platform thread.
Disadvantage of platform thread:
- It gets slow because thread creation takes time, Even with threadpool executer it used to limit the creation of
thread but still we get to create some threads.
- When thread is doing some task and it is idle for sometime, then the OS is also idle for that time, otherwise it
could use that time to do some other tasks.