Java Concurrent Programming - thread pool parameter configuration, thread pool configuration, thread pool monitoring

Keywords: Java

1, Parameter configuration of thread pool

1.corePoolSize core thread number selection

Before configuring the number of threads, you should first see whether the task type is IO intensive or CPU intensive?
What is IO intensive? For example, frequently read the data on the disk, or need to call the interface remotely through the network.
What is CPU intensive? For example, very complex calls, many cycles, or deep recursive calls.
The empirical value of threads in IO intensive configuration is 2N, where N represents the number of CPU cores.
The empirical value of threads in CPU intensive configuration is: N + 1, where N represents the number of CPU cores.

How to get the number of CPU cores?

int availableProcessors = Runtime.getRuntime().availableProcessors();

2.workQueue work queue (blocking queue) selection

There are three types of blocking queues commonly used in thread pools

BlockingQueue<Runnable> workQueue = null;
workQueue = new SynchronousQueue<>();//Unbuffered waiting queue
workQueue = new ArrayBlockingQueue<>(5);//Array based FIFO queue
workQueue = new LinkedBlockingQueue<>();//First in first out queue based on linked list

How to choose? Look at the difference between the three

Synchronous queue is a blocking queue that does not store elements. It is suitable for transitivity scenarios. It is only responsible for directly handing over the tasks submitted by the parent thread to the thread pool thread for processing. That is, if the number of tasks submitted exceeds the maximum number of threads, the reject policy will be executed

The bottom layer of ArrayBlockingQueue is a bounded blocking queue implemented by array, because the initial value needs to be passed (if the Integer maximum value is passed, it is also similar to unbounded). The queue sorts the elements according to the first in first out principle

The underlying layer of LinkedBlockingQueue is a bounded blocking queue implemented by linked list. If the initialization value is not passed as the maximum Integer value, the elements are sorted first in first out

Generally, it is recommended to select bounded queue, because if there are too many tasks and the core thread cannot handle them, the tasks will be put into the work queue. At this time, the maximum number of threads is meaningless. Poor control will lead to OOM

So which one do you choose between ArrayBlockingQueue and likedblockingqueue?

From the perspective of the underlying implementation, LikendBlockingQueue needs to maintain Node objects, which requires additional memory consumption. In addition, Node objects need to be created for insertion or removal during production and consumption. In systems with large quantities of data, it will have a great pressure on GC.

ArrayBlockingQueue only maintains final Object[] items; An array. During production and consumption, data is inserted or removed according to the index, and no additional object instances are generated or destroyed

In general, you can choose ArrayBlockingQueue.

3. Selection of blocking queue length and maximum number of threads

Most online answers to this question are judged according to project configuration and response time requirements, or calculated according to formulas. I think it should be selected according to the specific project. For example, it may be required to complete the requirements within a certain response time.

Take specific projects for example
Project requirements

1. Export the customer data from the project to pdf, then compress and download it
2. Use the thread pool sub thread to export the pdf of each customer, and use the main thread for compression
3. The export time of pdf for each customer is about 1.5s, with an average of 60 customers and a maximum of 150
4. The response time shall be completed within 3s

How should the length of the blocking queue and the maximum number of threads be set?
Because the response time is within 3s and each pdf generation takes 1.5s, a group of customers can be divided into two groups for execution, half of which are placed in the blocking queue and half of which are directly executed by creating non core threads. Group by the group with the largest number of people, then the maximum number of threads and the number of blocking queues are divided in half. You also need to consider the execution time of the main thread, so you can set a larger number of non core threads. The final result of the derivation is that the maximum number of threads can be set to 100, and the length of the blocking queue can also be set to 100. Remember to recycle non core threads and configure keepAlivedTime.

4. Reject policy selection

JDK provides four rejection policies

  • AbortPolicy: directly discard the new task and throw an exception
  • DiscardPolicy: discard it directly without throwing an exception
  • Discard oldest policy: discards the oldest task. Generally, it is the task at the front of the queue
  • CallerRunsPolicy: leave it to the main thread for execution

Of course, you can also customize the rejection policy. If your task cannot be rejected, you can return the task to the queue, re execute it, or hand it over to the main thread for execution. It will be written in the following example.

2, Configuring thread pool in SpringBoot environment

1. Thread pool configuration

Generally, in the Spring environment, we can hand over the ThreadPoolExecutor to Spring as a Bean. The configuration is as follows

//1.yml file configuration
demo:
  thread:
    coreSize: 8
    maxSize: 100
    keepAliveTime: 60
    queueLength: 100

//2. Read yml configuration file
@ConfigurationProperties(prefix = "demo.thread")
@Data
public class ThreadPoolConfigProperties {

    private Integer coreSize;

    private Integer maxSize;

    private Integer keepAliveTime;

    private Integer queueLength;

}

//3. Configure the bean of threadpoolector
@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
@Configuration
public class MyThreadConfig {

    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool){
        return new ThreadPoolExecutor(
                pool.getCoreSize(),
                pool.getMaxSize(),
                pool.getKeepAliveTime(),
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(pool.getQueueLength()),
                Executors.defaultThreadFactory(),
                new RejectedExecutionHandler() {
                    @SneakyThrows
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        while (executor.getQueue().offer(r,5,TimeUnit.SECONDS)){
                            break;
                        }
                    }
                }
        );
    }
}

//4. Use and test directly
 @Autowired
 private ThreadPoolExecutor executor;

 @RequestMapping("/threadtest")
 public void test(){
     for (int i = 0;i<100;i++){
         executor.execute(()->{
             System.out.println("sdf");
         });
     }
 }

Learn the next two notes
@ConfigurationProperties and @ EnableConfigurationProperties. To put it simply, @ EnableConfigurationProperties enables the class annotated by @ ConfigurationProperties to take effect, and takes the bean information annotated by @ ConfigurationProperties as the spring environment bean, which can directly fetch the data

2. Thread pool monitoring

Thread pool allows threads to be reused and managed, but improper use of thread pool may cause service downtime, memory overflow and other problems, so we can monitor thread pool. Thread pools provide methods to obtain relevant information

What's the use of getting this information? Remember the previous spring boot actuator? You can expose the running state of the thread pool through this mechanism, collect it through prometheus, and then display it.

Reference article:
Eight common rejection strategies: https://zhuanlan.zhihu.com/p/142254564
Thread pool enterprise applications: https://blog.csdn.net/AlbenXie/article/details/105292727

Posted by gabaod on Sun, 17 Oct 2021 23:31:35 -0700