The easiest way to use thread pool in springboot

Regarding the learning of threads and thread pools, we can start from the following aspects:

  • First, what is a thread, what is the difference between a thread and a process

  • Second, the basic concepts in threads, the life cycle of threads

  • Third, single-threaded and multi-threaded

  • Fourth, the principle analysis of the thread pool

  • Fifth, the characteristics of several common thread pools and their respective application scenarios

1. What is a thread

Thread, the smallest execution unit of program execution, is the actual operation unit in the process, and is often easily confused with the concept of process. So, what is the difference between a thread and a process? First of all, a process is a dynamic process and an active entity. To put it simply, the running of an application can be regarded as a process, and the thread is the actual task executor in running. It can be said that a process contains multiple threads that can run simultaneously.

Second, the life cycle of the thread

The life cycle of a thread can be better understood with the following diagram:

 

The first step is to use the new Thread() method to create a new thread. After the thread is created, the thread enters the ready (Runnable) state. At this time, the created thread enters the state of preempting CPU resources. When the thread grabs the CPU After the execution right, the thread enters the running state (Running), and when the task execution of the thread is completed or after the stop() method is abnormally called, the thread enters the dead state. And we can see from the diagram that the thread also has a blocking process. What's going on? When faced with the following situations, it is easy to cause thread blocking. First, when the thread actively calls the sleep() method, the thread will enter the blocked state. In addition, when the thread actively calls the block When the IO method is used, this method has a return parameter. Before the parameter is returned, the thread will also enter the blocked state. In another case, when the thread enters and is waiting for a notification, it will enter the blocked state. So, why is there a blocking state? We all know that CPU resources are very precious, so when a thread is performing a task of uncertain duration, Java will take back the execution right of the CPU, so as to use the CPU resources reasonably. We can see from the figure that after the blocking process ends, the thread will re-enter the ready state and grab CPU resources again. At this time, we may have a question, how to jump out of the blocking process? From the perspective of the above situations that may cause thread blocking, there is a time limit. When the sleep time of the sleep() method passes, the thread will Automatically jump out of the blocking state, the second is after returning a parameter, when the waiting notification is obtained, it automatically jumps out of the thread blocking process

3. What are single-threaded and multi-threaded?

Single thread, as the name suggests, means that only one thread is performing tasks. This situation is rarely encountered in our daily work and study, so we just do a brief understanding

Multi-threading, creating multiple threads to perform tasks at the same time, this method is more common in our daily life. However, in the process of using multithreading, there are still many concepts that we need to understand. For example, we need to understand the difference between parallelism and concurrency in understanding, as well as the safety issues of multi-threading in the actual application process.

Parallelism and concurrency: In our opinion, multiple tasks can be performed at the same time, so what is the difference between them?

Concurrency, from a macro point of view, concurrency is a variety of time at the same time, in fact, these kinds of time are not carried out at the same time, but alternately, and because the CPU's calculation speed is very fast, it will cause our The illusion that multiple things are going on at the same time

Concurrency is the true sense of doing multiple things at the same time. This can only be done on the basis of multi-core CPU.

There is a multi-threaded security issues? Why does it cause multi-threaded security issues? We can imagine that if multiple threads execute a task at the same time, the name means that they share the same resource, because the CPU resources of the threads may not be preempted by anyone. This is, the first thread preempts the CPU resources first. I just performed the first operation, and at this time the second thread seized the CPU resource, name, and the shared resource has not had time to change, and two pieces of data use the same resource at the same time. For details, please refer to the problem of multi-threaded ticket purchase. . How should we solve this problem?

We can see the cause of the problem. The main contradiction of this problem is that the preemption of the right to use the CPU conflicts with the sharing of resources. To solve the problem, we only need to let one thread occupy the resources of the CPU and prevent the second one. The thread seizes the execution right of the CPU at the same time. In the code, we only need to use the synchronization code block in the method. Here, the synchronization code block will not be described in detail, so you can understand it yourself.

Four, thread pool

From the above introduction, we can see that in an application, we need to use threads multiple times, which means that we need to create and destroy threads multiple times. The process of creating and destroying threads is bound to consume memory. In Java, memory resources are extremely precious, so we proposed the concept of thread pool.

Thread pool: A concept of thread management has been developed in Java. This concept is called thread pool. From the concept and application scenarios, we can see that the benefit of thread pool is that it can manage threads conveniently and reduce memory usage. consume.

So, how should we create a thread pool? Java already provides a class for creating a thread pool: Executor

When we create, we generally use its subclass: ThreadPoolExecutor.

public ThreadPoolExecutor(int corePoolSize,  
                              int maximumPoolSize,  
                              long keepAliveTime,  
                              TimeUnit unit,  
                              BlockingQueue workQueue,  
                              ThreadFactory threadFactory,  
                              RejectedExecutionHandler handler)
This is one of the most important construction methods, this method determines the various properties of the created thread pool, the following depends on A picture to better understand the thread pool and these parameters:

From the figure, we can see that the corePoolSize in the thread pool is the number of core threads in the thread pool. These core threads will not be recycled only when they are useless. The maximumPoolSize is the amount that can be accommodated in the thread pool. The maximum number of threads, and keepAliveTime, is the longest remaining time in the thread pool except for the core thread, because in the thread pool, except for the core thread, it cannot be cleared even if there is no task, and the rest All have survival time, which means the longest idle time that non-core threads can keep, and util is a unit for calculating this time, workQueue is a waiting queue, tasks can be stored in the task queue waiting to be executed, execute The first is the FIFIO principle (first in first out). threadFactory is a thread factory that creates threads. The last handler is a rejection strategy. We can refuse to execute certain tasks when the tasks are full.

What is the execution process of the thread pool?

 

From the figure, we can see that when a task comes in, the judgment is first performed to determine whether the core thread is idle. If not, the core thread executes the task first. If the core thread is full, it is judged whether the task queue has room to store the task. , if there is, save the task in the task queue and wait for execution. If it is full, judge the maximum number of threads that can be accommodated. If it does not exceed this number, create a non-core thread to execute the task. If it exceeds, call The handler implements the rejection policy.

Handler's rejection policy:

There are four types: the first AbortPolicy: no new tasks are executed, an exception is thrown directly, indicating that the thread pool is full

The second DisCardPolicy: does not execute new tasks and does not throw exceptions

The third DisCardOldSetPolicy: replace the first task in the message queue with the current new incoming task execution

The fourth CallerRunsPolicy: directly call execute to execute the current task

Five, four common thread pools:

CachedThreadPool: A cacheable thread pool. There are no core threads in this thread pool. The number of non-core threads is Integer.max_value, which is infinite. When necessary, threads are created to perform tasks, and threads are recycled when there is no need. It is suitable for time-consuming Few, heavy workload.

SecudleThreadPool: A thread pool that executes tasks periodically. It executes tasks in threads according to a specific plan. There are core threads, but there are also non-core threads. The size of non-core threads is also infinite. Suitable for performing periodic tasks.

SingleThreadPool: There is only one thread to execute tasks, which is suitable for application scenarios with sequential tasks.

FixedThreadPool: fixed-length thread pool, with core threads, the core thread is the maximum number of threads, no non-core threads

Six, thread pool

1. Configuration

@Configuration
@EnableAsync
public class TaskPoolConfig {

    @Bean("taskExecutor")
    public Executor taskExecutro(){
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(10);
        taskExecutor.setMaxPoolSize(50);
        taskExecutor.setQueueCapacity(200);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("taskExecutor--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(60);
        return taskExecutor;
    }


}

 2. Use

@Component
public class AsyncTask {
    private static Logger LOG = LoggerFactory.getLogger(AsyncTask.class.getName());

    @Autowired
    private DeformService deformService;

    @Async("taskExecutor")
    public void saveRawData(RawData rawData){
        LOG.info("saveRawData before thread:{}, imei:{},ts:{},rawData:{} ",Thread.currentThread().getName(), rawData.getImei(), rawData.getTs(), rawData.getRaw_data().length());
        int isSuccess = deformService.saveRawData(rawData);
        if (isSuccess == 1) {
            LOG.info("sation raw data is saved success. imei:{}", rawData.getImei());
        } else {
            LOG.info("sation raw data is saved failed. imei:{}", rawData.getImei());
        }
    }

    @Async("taskExecutor")
    public void saveCalcData(DeformData deform){
        LOG.info("saveCalcData before thread:{}, imei:{},ts:{}",Thread.currentThread().getName(), deform.getRover_imei(), deform.getTs());
        int isSuccess = deformService.saveCalcData(deform);
        if (isSuccess == 1) {
            LOG.info("sation calc data is saved success. imei:{}", deform.getRover_imei());
        } else {
            LOG.info("sation calc data is saved failed. imei:{}", deform.getRover_imei());
        }
    }

}

Guess you like

Origin blog.csdn.net/mawei7510/article/details/121232379