Multi-threaded thread pool ThreadPool


foreword

When we need to perform a large number of operations, the rate of single-threaded synchronous operations obviously cannot meet our needs. At this time, we need to use multi-threading technology, and use multiple threads to process multiple tasks at the same time. If there is no data exchange between threads, we can use asynchronous methods to speed up the execution of tasks.
The creation and destruction of threads need to occupy resources, and thread pool technology must be used at this time.


1. The operation process of the thread pool

The role of the thread pool is to pre-create several threads ( core threads ). The life cycle of the core thread is consistent with the thread pool. It is created with the creation of the thread pool and destroyed with the destruction of the thread pool .
When the core thread is full, the newly submitted tasks will be queued in the blocking queue. When the core thread is idle, the tasks in the blocking queue will be processed immediately.
When the thread finishes executing the assigned task, it will return to the thread pool and wait for the next call.
When the blocking queue is empty and the threads are idle for more than a specific time, the thread pool will destroy the redundant threads, keep the threads that are still running, and keep at least "core threads" threads.
Therefore, to use thread pool technology, you only need to define a few attributes in the thread pool, and the thread pool will automatically complete tasks such as assigning tasks, creating threads, reusing idle threads, and recycling idle threads for you.

insert image description here

2. Thread pool implementation class ThreadPoolTaskExcutor

1. Import library

The code is as follows (example):

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

2. Seven parameters of the thread pool

The seven parameters of the thread pool are corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler

(1) corePoolSize: the number of resident core threads in the thread pool

(2) maximumPoolSize: The thread pool can accommodate the maximum number of threads executed at the same time

(3) keepAliveTime: Survival time of redundant idle threads

(4) unit: the time unit of keepAliveTime

(5) workQueue: task queue, tasks that have been submitted but not yet executed

(6) threadFactory: Indicates the thread factory that generates the worker threads in the thread pool

(7) handler: Rejection strategy, indicating how to reject when the queue is full and the worker thread is greater than or equal to the maximum number of threads in the thread pool (maximumPoolSize).


3. Tool code

Example:

public class ExecutorUtil {
    //获取当前机器的核数
//    public static final int cpuNum = Runtime.getRuntime().availableProcessors();

    public static Executor getAsyncExecutor(Integer corePoolSize, Integer maxPoolSize) {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setMaxPoolSize(maxPoolSize);//最大线程大小
        taskExecutor.setCorePoolSize(corePoolSize);//核心线程大小
        //队列最大容量,默认为Integer的最大值,全程异步队列设为0
//        taskExecutor.setQueueCapacity(0);
        taskExecutor.setQueueCapacity(1000);
        //当提交的任务个数大于QueueCapacity,就需要设置该参数,但spring提供的都不太满足业务场景,可以自定义一个,也可以注意不要超过QueueCapacity即可
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);// 设置关闭时是否等待任务完成
        taskExecutor.setAwaitTerminationSeconds(60);// 等待终止的秒数,就是上面说的空闲多长时间会销毁
        taskExecutor.setThreadNamePrefix("Thread-");// 设置线程名前缀
        taskExecutor.initialize();
        return taskExecutor;
    }
}

4. Setting parameter skills

(1) Number of core threads and maximum number of threads:

CPU-intensive:
Maximum number of threads = number of CPU cores + 1
core thread number = maximum number of threads * 20%

IO-intensive:
Maximum number of threads = number of CPU cores * 2
core threads = maximum number of threads * 20%

It is best to let someone with extensive experience specify the two parameters according to the actual situation.

(2) Blocking queue:
If the whole process is asynchronous, it can be set to 0 (the threads are completely independent, there is no data exchange, and there is no need to wait for the synchronous signal to return).
If you set a non-zero number such as 1000, the maximum number of blocking queues will be 1000, plus the maximum number of threads, it will remain at around 1000, effectively limiting the amount of concurrency.
If the blocking queue is not set, it defaults to the maximum value of Integer. It is not recommended to set this way. When the concurrency is small, the blocking queue cannot be filled, and non-core threads cannot be enabled; when the blocking queue can be filled, the concurrency It will be very big, and the pressure on the server will also be great. Therefore, it is still recommended to set a blocking queue length, and it is best to set an appropriate value according to the concurrency and computer performance.


5. Specific use

import org.example.util.ExecutorUtil;
import java.util.concurrent.Executor;

Executor executor = ExecutorUtil.getAsyncExecutor(CORE_POOL_NUM, MAX_POOL_NUM);
……// 此处应该是一个循环体for或while,重复提交任务到线程池
	executor.execute(() -> {
		……// 需要并发执行的方法
		});

Summarize

This article describes the principle and basic process of the thread pool, and provides template code, hoping to come in handy when readers need it!

Guess you like

Origin blog.csdn.net/War_wick/article/details/129164138