Thread pool tuning of Java multithreading
default allocation
- corePoolSize=1
- queueCapacity=Integer.MAX_VALUE
- maxPoolSize=Integer.MAX_VALUE
- keepAliveTime=60s
- allowCoreThreadTimeout=false
- rejectedExecutionHandler=AbortPolicy()
shortcoming
- The initial value of corePoolSize core thread is 1 too little
- The queueCapacity and maxPoolSize are set so large, I am afraid that there are too many threads and the system can't stand it
- The rejectedExecutionHandler can be changed
How to optimize
Need to decide based on several values
- tasks : the number of tasks per second, assuming 500~1000
- taskcost: the time spent on each task, assuming 0.1s
- responsetime: the maximum response time that the system allows to tolerate, assuming 1s
do some calculations
corePoolSize = How many threads per second are required?
- threadcount = tasks/(1/taskcost) =tasks*taskcout = (500~1000)*0.1 = 50~100 threads. corePoolSize setting should be greater than 50
- According to the 8020 principle, if 80% of the tasks per second are less than 800, then the corePoolSize can be set to 80
queueCapacity = (coreSizePool/taskcost)*responsetime
- It can be calculated that queueCapacity = 80/0.1*1 = 80. It means that the threads in the queue can wait for 1s, and if it exceeds, a new thread needs to be opened to execute
- Remember that it cannot be set to Integer.MAX_VALUE, so the queue will be very large, and the number of threads will only remain at the corePoolSize size. When the task increases sharply, new threads cannot be opened for execution, and the response time will increase sharply.
maxPoolSize = (max(tasks)- queueCapacity)/(1/taskcost)
- Calculated to get maxPoolSize = (1000-80)/10 = 92
- (Maximum number of tasks - queue capacity) / processing capacity per thread per second = maximum number of threads
rejectedExecutionHandler : It is determined according to the specific situation. The task is not important and can be discarded. If the task is important, some buffering mechanisms should be used to process it.
keepAliveTime and allowCoreThreadTimeout are usually satisfied by default
The above are all ideal values, which should be determined according to the performance of the machine in actual situations. If the cpu load of the machine is full before the maximum number of threads is reached, you need to upgrade the hardware (hehe) and optimize the code to reduce the task cost to deal with it.
some experience
dev configuration
- corePoolSize=20
- queueCapacity=100
- maxPoolSize=150
- keepAliveTime=300s
- waitForTasksToCompleteOnShutdown=true, finish the task first and then shutdown
- rejectedExecutionHandler=CallerRunsPolicy(), let the calling thread continue to complete the task
prod configuration
- corePoolSize=20
- queueCapacity=200
- maxPoolSize=500
- keepAliveTime=300s
- waitForTasksToCompleteOnShutdown=true, finish the task first and then shutdown
- rejectedExecutionHandler=CallerRunsPolicy(), let the calling thread continue to complete the task
suggestion
In practice, it is recommended to do a stress test first, try to use the ideal number of threads during the test, check the upper limit of threads, and then gradually adjust the thread pool.