10 Definitions of Each Parameter in the Thread Pool

10 Definitions of Each Parameter in the Thread Pool #

In this lesson, we mainly learn the meaning of the parameters of a thread pool, and focus on understanding when the threads in a thread pool are created and destroyed.

Parameters of ThreadPool #

img

First, let’s take a look at the meanings of the parameters in the thread pool, as shown in the table. The thread pool has 6 parameters, and the third parameter is composed of keepAliveTime and the time unit. Let’s see their respective meanings one by one. The corePoolSize is the number of core threads, which is the number of threads in the persistent thread pool. Corresponding to it is the maximumPoolSize, which represents the maximum number of threads in the thread pool. When we have a lot of tasks and the corePoolSize is not enough to meet the demand, we will add threads to the thread pool to handle the surge of tasks.

Timing of Thread Creation #

img

Next, let’s take a closer look at the meanings of these two parameters and the timing of thread creation in the thread pool. As shown in the above figure, after a task is submitted, the thread pool first checks the current number of threads. If the number of threads is smaller than the core pool size, for example, if the initial number of threads is 0, a new thread will be created and the task will be executed. As tasks continue to increase, the number of threads will gradually increase until it reaches the core pool size. At this point, if tasks continue to be submitted, they will be put into the workQueue task queue and wait to be executed when the core threads finish the current task.

Now, let’s assume that we have a large number of tasks and have reached the capacity limit of the workQueue. At this time, the thread pool will activate the backup plan, which is the maximumPoolSize. The thread pool will continue to create threads on top of the corePoolSize to execute tasks. Assuming that tasks continue to be submitted, the thread pool will continue to create threads until the number of threads reaches the maximumPoolSize. If tasks are still being submitted and exceed the maximum processing capacity of the thread pool, the thread pool will reject these tasks. As we can see, after tasks come in, the thread pool will evaluate corePoolSize, workQueue, and maximumPoolSize one by one. If the requirements are still not met, the tasks will be rejected.

corePoolSize and maximumPoolSize #

Through the above flowchart, we have learned the specific meanings of corePoolSize and maximumPoolSize. corePoolSize refers to the number of core threads. When the thread pool is initialized, the number of threads defaults to 0. When a new task is submitted, a new thread is created to execute the task. If no special settings are made, the number of threads will usually not be smaller than corePoolSize, because they are core threads that will not be destroyed even if there may be no executable tasks in the future. As the number of tasks increases, after the task queue is full, the thread pool will continue to create new threads, up to maximumPoolSize, to cope with scenarios where there are many tasks. If there are idle threads in the future, threads greater than corePoolSize will be reclaimed appropriately. Therefore, under normal circumstances, the number of threads in the thread pool will be within the closed interval of corePoolSize and maximumPoolSize.

“Regular Workers” and “Temporary Workers” #

We can compare corePoolSize and maximumPoolSize to regular workers and temporary workers, respectively. In ancient times, a large household would have several regular workers responsible for daily tasks. Initially, the large household would hire regular workers from scratch. If the number of regular workers is set to 5, it corresponds to corePoolSize. Regardless of whether these 5 regular workers are busy or idle, they will always stay with the large household. However, during busy farming seasons or holidays like the Spring Festival, it is apparent that the number of regular workers is not sufficient. At this time, more temporary workers are needed. These temporary workers can be seen as creating new threads based on corePoolSize. However, there is also a limit to the number of temporary workers, corresponding to maximumPoolSize. As the busy farming season or holiday ends, considering labor costs, the employer may terminate the contracts of these temporary workers, reducing the number of workers in the household from maximumPoolSize to corePoolSize. Therefore, the number of workers in the household will always remain within the range of corePoolSize and maximumPoolSize.

img

Here, we use an animation to vividly describe the entire process of the thread pool. For example, the corePoolSize of the thread pool is set to 5, and the maximumPoolSize is set to 10, with a task queue capacity of 100. As tasks are submitted, the number of threads gradually increases from 0 to 5. After that, it stops growing, and new tasks are placed in the queue until the queue is full. Then, new threads are created based on corePoolSize to execute the tasks in the queue. The number of threads gradually increases to maximumPoolSize, and then it stops increasing. If tasks continue to be submitted at this time, the thread pool will reject the tasks. As the tasks in the queue are executed, the 10 created threads are idle. At this point, the thread pool will destroy threads based on the keepAliveTime parameter to reduce memory usage.

Through understanding the flowchart and demonstration animation, we can summarize several characteristics of the thread pool:

  • The thread pool aims to maintain a small number of threads and only increases threads when the load becomes heavy.
  • The thread pool creates more threads than corePoolSize only when the task queue is filled. If an unbounded queue (such as LinkedBlockingQueue) is used, the number of threads will not exceed corePoolSize because the queue will not be full.
  • By setting corePoolSize and maximumPoolSize to the same value, a fixed-size thread pool can be created.
  • By setting a very high value for maximumPoolSize, such as Integer.MAX_VALUE, the thread pool can create an arbitrary number of threads.

keepAliveTime+TimeUnit #

The third parameter is keepAliveTime + TimeUnit. When the number of threads in the thread pool is greater than the core thread count, and there are no tasks to be done at that time, the thread pool will check the keepAliveTime of the threads. If the specified time is exceeded and there are no tasks for the threads to do, the idle threads will be destroyed to reduce memory usage and resource consumption. If more tasks are added later, the thread pool will dynamically create threads according to the rules. Therefore, this is a scalable process and quite flexible. We can also use the setKeepAliveTime method to dynamically change the value of the keepAliveTime parameter.

ThreadFactory #

The fourth parameter is the ThreadFactory, which is actually a factory for creating threads to execute tasks. We can choose to use the default ThreadFactory, which creates threads in the same thread group with the same priority and are not daemon threads. We can also choose to customize our own ThreadFactory to give threads custom names, as threads in different thread pools often have different thread names based on specific business requirements.

workQueue and Handler #

The last two parameters are workQueue and Handler, which correspond to the blocking queue and task rejection policy, respectively. They will be discussed in detail in the following lessons.

In this lesson, we have introduced the meanings of various parameters of the thread pool, as well as how the thread pool responds when tasks are submitted, and when new threads are created and destroyed. Do you find the design of the thread pool ingenious?