springboot线程池基础监控

代码

代码类结构
  • ThreadPoolMonitor:线程池扩展类
  • ThreadPoolUtil:线程池工具类
  • ThreadPoolDetailInfo:bean类
  • ExecutorThreadPoolManager:线程池实现类
  • ThreadPoolController:线程池测试方法

线程池扩展类
  • 从类主要重写了ThreadPoolExecutor类中的shutdown/shutdownNow/beforeExecute/afterExecute,用于对每个任务进行执行前后的拦截,计算出每个任务的运行时间。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;


/**
 * @ClassName ThreadPoolMonitor
 * @desc 线程池扩展类
 * @authors ruicm
 * @Date 2023/12/04 19:45
 **/
public class ThreadPoolMonitor extends ThreadPoolExecutor {
    private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolMonitor.class);
    private final ConcurrentHashMap<String, Date> startTimes;
    private final String poolName;
    private long totalDiff;

    public ThreadPoolMonitor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, String poolName) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        this.startTimes = new ConcurrentHashMap();
        this.poolName = poolName;
    }

    @Override
    public void shutdown() {
        LOGGER.info("{} Going to shutdown. Executed tasks: {}, Running tasks: {}, Pending tasks: {}", new Object[]{this.poolName, this.getCompletedTaskCount(), this.getActiveCount(), this.getQueue().size()});
        super.shutdown();
    }
    @Override
    public List<Runnable> shutdownNow() {
        LOGGER.info("{} Going to immediately shutdown. Executed tasks: {}, Running tasks: {}, Pending tasks: {}", new Object[]{this.poolName, this.getCompletedTaskCount(), this.getActiveCount(), this.getQueue().size()});
        return super.shutdownNow();
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        this.startTimes.put(String.valueOf(r.hashCode()), new Date());
    }
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        Date startDate = this.startTimes.remove(String.valueOf(r.hashCode()));
        Date finishDate = new Date();
        long diff = finishDate.getTime() - startDate.getTime();
        this.totalDiff += diff;
    }

    public long getTotalDiff() {
        return this.totalDiff;
    }
}
线程工具类

import cn.*.ThreadPoolMonitor;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;


/**
 * @ClassName ThreadPoolUtil
 * @authors ruicm
 * @Date 2023/12/04 19:45
 **/
@Component
public class ThreadPoolUtil {

    private final HashMap<String, ThreadPoolMonitor> threadPoolExecutorHashMap = new HashMap();

    public ThreadPoolUtil() {
    }

    public ThreadPoolMonitor creatThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,String poolName) {
        ThreadPoolMonitor threadPoolExecutor = new ThreadPoolMonitor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,threadFactory, poolName);
        this.threadPoolExecutorHashMap.put(poolName, threadPoolExecutor);
        return threadPoolExecutor;
    }

    public HashMap<String, ThreadPoolMonitor> getThreadPoolExecutorHashMap() {
        return this.threadPoolExecutorHashMap;
    }
}
线程bean类

import lombok.Data;

@Data
public class ThreadPoolDetailInfo {
    //线程池名字
    private String threadPoolName;
    //当前线程池大小
    private Integer poolSize;
    //线程池核心线程数量
    private Integer corePoolSize;
    //线程池生命周期中最大线程数量
    private Integer largestPoolSize;
    //线程池中允许的最大线程数
    private Integer maximumPoolSize;
    //线程池完成的任务数目
    private long completedTaskCount;
    //线程池中当前活跃个数
    private Integer active;
    //线程池完成的任务个数
    private long task;
    //线程最大空闲时间
    private long keepAliveTime;
    //当前活跃线程的占比
    private int activePercent;
    //任务队列容量(阻塞队列)
    private Integer queueCapacity;
    //当前队列中任务的数量
    private Integer queueSize;
    //线程池中任务平均执行时长
    private long avgExecuteTime;

    public ThreadPoolDetailInfo(String threadPoolName, Integer poolSize, Integer corePoolSize, Integer largestPoolSize, Integer maximumPoolSize, long completedTaskCount, Integer active, long task, long keepAliveTime, int activePercent, Integer queueCapacity, Integer queueSize, long avgExecuteTime) {
        this.threadPoolName = threadPoolName;
        this.poolSize = poolSize;
        this.corePoolSize = corePoolSize;
        this.largestPoolSize = largestPoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.completedTaskCount = completedTaskCount;
        this.active = active;
        this.task = task;
        this.keepAliveTime = keepAliveTime;
        this.activePercent = activePercent;
        this.queueCapacity = queueCapacity;
        this.queueSize = queueSize;
        this.avgExecuteTime = avgExecuteTime;
    }
}
线程池实现类
  • 在我的项目中,将线程池依次划分为high、normal、low、single四种线程池类型。不同优先级的任务将会被submit到不同的线程池中执行。
  • 在业务中有判断线程池中queue的长度来决定是否投递任务,由于没有相应的拒绝策略,所以队列不设置长度。

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.*.ThreadPoolUtil;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Component
public class ExecutorThreadPoolManager {

    @Autowired
    private ThreadPoolUtil threadPoolUtil;

    @Value("${thread.pool.normal.level.thread.max-num}")
    private Integer normalLevelThreadPoolThreadMaxNum;
    @Value("${thread.pool.normal.level.core.thread-num}")
    private Integer normalLevelThreadPoolCoreThreadNum;
    @Value("${thread.pool.low.level.thread.max-num}")
    private Integer lowLevelThreadPoolThreadMaxNum;
    @Value("${thread.pool.low.level.core.thread-num}")
    private Integer lowLevelThreadPoolCoreThreadNum;

    private ThreadPoolExecutor normalThreadPoolExecutor;

    private ThreadPoolExecutor highPriorityExecutor;

    private ThreadPoolExecutor lowPriorityExecutor;

    private ThreadPoolExecutor singleThreadPoolExecutor;


    @PostConstruct
    public void initExecutor() {
        ThreadFactory normalThreadFactory = new ThreadFactoryBuilder().setNameFormat("normal_task_thread_%d").build();
        normalThreadPoolExecutor = threadPoolUtil.creatThreadPool(normalLevelThreadPoolCoreThreadNum, normalLevelThreadPoolThreadMaxNum, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), normalThreadFactory,"normal_level_thread_pool");

        ThreadFactory highPriorityThreadFactory = new ThreadFactoryBuilder().setNameFormat("high_priority_level_task_thread_%d").build();
        highPriorityExecutor = threadPoolUtil.creatThreadPool(normalLevelThreadPoolCoreThreadNum, normalLevelThreadPoolThreadMaxNum, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), highPriorityThreadFactory,"high_level_thread_pool");

        ThreadFactory lowPriorityThreadFactory = new ThreadFactoryBuilder().setNameFormat("low_priority_level_task_thread_%d").build();
        lowPriorityExecutor = threadPoolUtil.creatThreadPool(lowLevelThreadPoolCoreThreadNum, lowLevelThreadPoolThreadMaxNum, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), lowPriorityThreadFactory,"low_level_thread_pool");

        ThreadFactory singleFactory = new ThreadFactoryBuilder().setNameFormat("single_task_thread_%d").build();
        singleThreadPoolExecutor =threadPoolUtil.creatThreadPool(1, 1,
                0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), singleFactory,"single_level_thread_pool");
    }

    /**
     * @author ruicm
     * @date 2023/12/05
     * @describe 定义三种线程池, 一般采集类的用低优, 正常业务的用中优, 用户手动请求API的用高优线程池
     **/
    public ThreadPoolExecutor getNormalThreadPoolExecutor() {
        return normalThreadPoolExecutor;
    }

    public ThreadPoolExecutor getHighPriorityExecutor() {
        return highPriorityExecutor;
    }

    public ThreadPoolExecutor getLowPriorityExecutor() {
        return lowPriorityExecutor;
    }

    public ThreadPoolExecutor getSingleThreadPoolExecutor() {
        return singleThreadPoolExecutor;
    }
线程池监控接口类

运行结果

  • 上面controller中的方法除了可以通过接口进行暴露外,还设置了定时任务定期的打印到日志中。方便对系统状态进行排查。
[
  {
    "threadPoolName": "high_level_thread_pool",
    "poolSize": 0,
    "corePoolSize": 10,
    "largestPoolSize": 0,
    "maximumPoolSize": 20,
    "completedTaskCount": 0,
    "active": 0,
    "task": 0,
    "keepAliveTime": 0,
    "activePercent": 0,
    "queueCapacity": 0,
    "queueSize": 0,
    "avgExecuteTime": 0
  },
  {
    "threadPoolName": "low_level_thread_pool",
    "poolSize": 0,
    "corePoolSize": 15,
    "largestPoolSize": 0,
    "maximumPoolSize": 15,
    "completedTaskCount": 0,
    "active": 0,
    "task": 0,
    "keepAliveTime": 0,
    "activePercent": 0,
    "queueCapacity": 0,
    "queueSize": 0,
    "avgExecuteTime": 0
  },
  {
    "threadPoolName": "normal_level_thread_pool",
    "poolSize": 0,
    "corePoolSize": 10,
    "largestPoolSize": 0,
    "maximumPoolSize": 20,
    "completedTaskCount": 0,
    "active": 0,
    "task": 0,
    "keepAliveTime": 0,
    "activePercent": 0,
    "queueCapacity": 0,
    "queueSize": 0,
    "avgExecuteTime": 0
  },
  {
    "threadPoolName": "single_level_thread_pool",
    "poolSize": 0,
    "corePoolSize": 1,
    "largestPoolSize": 0,
    "maximumPoolSize": 1,
    "completedTaskCount": 0,
    "active": 0,
    "task": 0,
    "keepAliveTime": 0,
    "activePercent": 0,
    "queueCapacity": 0,
    "queueSize": 0,
    "avgExecuteTime": 0
  }
]

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在配置Spring Boot线程池时,合理配置核心参数是非常重要的。以下是一些建议: 1. 核心线程数(corePoolSize):核心线程数是线程池中同时执行任务的最小线程数。根据应用程序的负载和资源限制,可以根据需求进行调整。通常,它应该设置为能够处理正常负载的数量,以避免过多的线程创建和销毁开销。如果你的应用程序是CPU密集型任务,可以设置为CPU核心数的两倍左右。 2. 最大线程数(maxPoolSize):最大线程数是线程池中允许存在的最大线程数。如果任务量超过了核心线程数,线程池会创建新的线程来执行任务,直到达到最大线程数。根据系统负载和资源限制,可以根据需求进行调整。一般情况下,最大线程数应该根据系统资源限制来设置,以避免过多的线程造成系统资源耗尽。 3. 队列容量(queueCapacity):队列容量是用于存放等待执行任务的队列大小。当所有核心线程都在执行任务并且队列已满时,新任务会被拒绝执行。根据应用程序的需求和系统资源限制,可以根据需求进行调整。如果任务的到达速率很高,可以考虑使用无界队列(如`LinkedBlockingQueue`),以避免任务被拒绝执行。 4. 线程存活时间(keepAliveTime):线程存活时间是非核心线程的空闲时间,超过该时间将被终止。这个参数主要适用于非核心线程,因为核心线程始终保持活动状态。根据应用程序的负载和响应时间要求,可以根据需求进行调整。 请注意,以上参数的合理配置取决于你的应用程序需求、系统资源和预期的性能表现。通过监控和测试,可以进行适当的调整和优化。 希望这些信息对你有所帮助!如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值