SpringBoot 整合线程池及各参数详解

2021-02-09  本文已影响0人  大程子的技术成长路

代码结构自上而下

ThreadPoolConfig

package com.studymongo.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
* 线程池配置类
* @author wangcp
* @date 2021/02/09 11:19
**/
@Data
@EnableAsync
@Configuration
@ConfigurationProperties(prefix = "poolconfig")
public class ThreadPoolConfig {

    /**
     * 线程池维护线程的最少数量,即使没有任务需要执行,也会一直存活
     */
    private int corePoolSize;

    /**
     * 线程池维护线程的最大数量
     */
    private int maxPoolSize;

    /**
     * 缓存队列(阻塞队列)当核心线程数达到最大时,新任务会放在队列中排队等待执行
     */
    private int queueCapacity;

    /**
     * 允许的空闲时间,当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
     */
    private int keepAlive;


    @Bean
    public TaskExecutor taskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心线程数
        executor.setCorePoolSize(corePoolSize);
        // 设置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        // 设置队列容量
        executor.setQueueCapacity(queueCapacity);
        // 设置允许的空闲时间(秒)
        executor.setKeepAliveSeconds(keepAlive);
        // 设置默认线程名称
        executor.setThreadNamePrefix("thread-");
        // 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALL_RUNS:不在新线程中执行任务,二十由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后在关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

ThreadController

package com.studymongo.controller;

import com.studymongo.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* 线程测试控制类
* @author wangcp
* @date 2021/02/09 11:32
**/
@RestController
public class ThreadController {

    @Autowired
    private AsyncService asyncService;

    @GetMapping(value = "/thread")
    public void thread(){
        asyncService.executeAsync();
    }
}

AsyncService

package com.studymongo.service;

public interface AsyncService {
    void executeAsync();
}

AsyncServiceImpl

package com.studymongo.service.impl;

import com.studymongo.service.AsyncService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/**
* 实现类
* @author wangcp
* @date 2021/02/09 11:35
**/
@Slf4j
@Service
public class AsyncServiceImpl implements AsyncService {

    @Async("taskExecutor")
    @Override
    public void executeAsync() {
        log.info("start executeAsync");
        try {
            System.out.println("当前运行线的程名称:" + Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("end executeAsync");
    }
    
}

application.yaml

poolconfig:
  corePoolSize: 3
  maxPoolSize: 6
  queueCapacity: 10
  keepAlive: 100

运行结果

image-20210209140558610.png
根据运行结果发现,线程运行时有序的!

线程池的各个参数详解

参数默认值及含义

# 线程池维护线程的最少数量,即使没有任务需要执行,也会一直存活
private int corePoolSize = 1;

# 线程池维护线程的最大数量
private int maxPoolSize = 2147483647;

# 允许的空闲时间,当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
private int keepAliveSeconds = 60;

# 缓存队列(阻塞队列)当核心线程数达到最大时,新任务会放在队列中排队等待执行
private int queueCapacity = 2147483647;

#拒绝策略
rejectedExecutionHandler = AbortPolicy()

对照源码解析,可以得出以下结论:

1.如果线程池中线程数量 < 核心线程数,新建一个线程执行任务;

2.如果线程池中线程数量 >= 核心线程数,则将任务放入任务队列

3.如果线程池中线程数量 >= 核心线程数 且 < maxPoolSize,且任务队列满了,则创建新的线程;

4.如果线程池中线程数量 > 核心线程数,当线程空闲时间超过了keepalive时,则会销毁线程;由此可见线程池的队列如果是无界队列,那么设置线程池最大数量是无效的;

5.如果线程池中的任务队列满了,而且线程数达到了maxPoolSize,并且没有空闲的线程可以执行新的任务,这时候再提交任务就会执行拒绝策略

拒绝策略详解

拒绝策略RejectedExecutionHandler分为以下5种

image-20210209142923446.png

结论

这几种策略没有好坏之分,只是适用不同场景,具体哪种合适根据具体场景和业务需要选择,如果需要特殊处理就自己定义好了。

上一篇 下一篇

猜你喜欢

热点阅读