线程池中线程数和队列的类型及长度对线程会造成很大的影响,而且会争夺系统稀有资源,线程数。设置不当,或是没有最大的利用系统资源,提高系统的整体运行效率,或是导致整个系统的故障。典型的场景是线程数被占满,其他的请求无响应。或是任务积压过多,直接oom
方便的排查线程中的故障以及优化线程池的使用
5.2、监控的原理另起一个定时单线程数的线程池newSingleThreadScheduledExecutor
调用scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)定时执行监控任务;
定时任务内 通过ThreadPoolExecutor对象获取监控的对象信息,比如t线程池需要执行的任务数、线程池在运行过程中已完成的任务数、曾经创建过的最大线程数、线程池里的线程数量、线程池里活跃的线程数量、当前排队线程数
根据预设的日志或报警策略,进行规则控制
5.3、实现的细节定义线程池并启动监控
/** * 定义线程池的队列的长度 */ private final Integer queueSize = 1000; /** * 定义一个定长的线程池 */ private ExecutorService executorService; @PostConstruct private void initExecutorService() { log.info( "executorService init with param: threadcount:{} ,queuesize:{}", systemConfig.getThreadCount(), systemConfig.getThreadQueueSize()); executorService = new ThreadPoolExecutor( systemConfig.getThreadCount(), systemConfig.getThreadCount(), 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(systemConfig.getThreadQueueSize()), new BasicThreadFactory.Builder() .namingPattern("async-sign-thread-%d") .build(), (r, executor) -> log.error("the async executor pool is full!!")); /** 启动线程池的监控 */ ThreadPoolMonitoring threadPoolMonitoring = new ThreadPoolMonitoring(); threadPoolMonitoring.init(); }线程池的监控
/** * 功能说明:线程池监控 * * @params * @return <br> * 修改历史<br> * [2019年06月14日 10:20:10 10:20] 创建方法by fengqingyang */ public class ThreadPoolMonitoring { /** 用于周期性监控线程池的运行状态 */ private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new BasicThreadFactory.Builder() .namingPattern("async thread executor monitor") .build()); /** * 功能说明:自动运行监控 * * @return <br> * 修改历史<br> * [2019年06月14日 10:26:51 10:26] 创建方法by fengqingyang * @params */ public void init() { scheduledExecutorService.scheduleAtFixedRate( () -> { try { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService; /** 线程池需要执行的任务数 */ long taskCount = threadPoolExecutor.getTaskCount(); /** 线程池在运行过程中已完成的任务数 */ long completedTaskCount = threadPoolExecutor.getCompletedTaskCount(); /** 曾经创建过的最大线程数 */ long largestPoolSize = threadPoolExecutor.getLargestPoolSize(); /** 线程池里的线程数量 */ long poolSize = threadPoolExecutor.getPoolSize(); /** 线程池里活跃的线程数量 */ long activeCount = threadPoolExecutor.getActiveCount(); /** 当前排队线程数 */ int queueSize = threadPoolExecutor.getQueue().size(); log.info( "async-executor monitor. taskCount:{}, completedTaskCount:{}, largestPoolSize:{}, poolSize:{}, activeCount:{},queueSize:{}", taskCount, completedTaskCount, largestPoolSize, poolSize, activeCount, queueSize); /** 超过阀值的80%报警 */ if (activeCount >= systemConfig.getThreadCount() * 0.8) { log.error( "async-executor monitor. taskCount:{}, completedTaskCount:{}, largestPoolSize:{}, poolSize:{}, activeCount:{},queueSize:{}", taskCount, completedTaskCount, largestPoolSize, poolSize, activeCount, queueSize); ; } } catch (Exception ex) { log.error("ThreadPoolMonitoring service error,{}", ex.getMessage()); } }, 0, 30, TimeUnit.SECONDS); } } 6、需要注意的事项线程数要合理设置,一般建议值是核数的2倍。
线程池队列的类型和长度要根据业特性合理设置
不同的业务需要线程池隔离,避免相互影响
未每个线程池增加特有的命名规范以及关键的日志,方便出问题排查和优化