线程池监控与动态参数调整设计

    为了提高系统吞吐量,系统使用线程池越来越多。由于缺乏对线程池的统一监控手段,运营人员不知道线程池的具体运行情况,不利于线程池的性能调优。
   开发线程池监控系统,对系统中的线程池进行统一监控。

详细代码参见utils

(一)线程池运行时数据的收集与展示

  1. 定义线程池统计数据接口ExecutorMonitorData,用于获取线程池的运行时数据,包括所属服务、线程池名称、线程池的唯一标识(线程池一般随系统启动而启动,随系统关闭而关闭)、核心线程数、当前线程数、历史最大线程、最大线程数、当前活跃线程数、最大空闲时间、当前任务数、已完成数量、任务执行总时间、任务执行最长时间、最短时间、排队最初时间、排队最短时间、执行超时次数、异常次数、排队超时次数、拒绝次数、阻塞队列、线程工厂、拒绝策略、启动时间。
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 定义监控数据接口
 */
public interface ExecutorMonitorData {
	/**
	 * 线程池启动时间
	 */
	Date getStartTime();

	/**
	 * 线程池所在服务
	 */
	String getService();

	/**
	 * 线程池名字,每个线程池有一个唯一的名字,比如HttpRequest、DbExecutor
	 */
	String getPoolName();

	/**
	 * 线程池的唯一标识,因为线程池可能因为重启等因素被关闭,但是要唯一区别一个线程池,所以不能使用{@link ExecutorMonitorData#getPoolName()},
	 * 建议的格式为{@link top.jfunc.common.thread.monitor.generator.CommonIdentifierGenerator}
	 */
	String getIdentifier();

	/**
	 * 当前核心线程数
	 */
	int getPoolSize();

	/**
	 * 配置的核心线程数
	 */
	int getCorePoolSize();

	/**
	 * 历史到达最大线程数
	 */
	int getLargestPoolSize();

	/**
	 * 配置的最大线程数
	 */
	int getMaximumPoolSize();

	/**
	 * 当前活跃线程数
	 */
	int getActiveCount();

	/**
	 * 线程最大空闲时间
	 */
	long getKeepAliveTime(TimeUnit timeUnit);

	/**
	 * 是否允许核心线程空闲回收
	 */
	boolean allowsCoreThreadTimeOut();

	/**
	 * 当前任务数
	 */
	long getTaskCount();

	/**
	 * 已完成任务数
	 */
	long getCompletedTaskCount();

	/*BlockingQueue<Runnable> getQueue();

	ThreadFactory getThreadFactory();

	RejectedExecutionHandler getRejectedExecutionHandler();*/

    /**
     * 阻塞队列容量
     */
	int getQueueCapacity();

    /**
     * 阻塞队列当前数量
     */
	int getQueueSize();

    /**
     * 阻塞队列的类名
     */
	String getQueueClass();
    /**
     * 线程工厂的类名
     */
	String getThreadFactoryClass();
    /**
     * 拒绝策略的类名
     */
	String getRejectedExecutionHandlerClass();

	/**
	 * 任务执行总时间,依赖于{@link top.jfunc.common.thread.monitor.adapter.MonitoredThreadPoolExecutor}和{@link StatisticsRunnable}
	 */
	long getTotalExecuteTime();
    /**
     * 任务执行最小时间,依赖于{@link top.jfunc.common.thread.monitor.adapter.MonitoredThreadPoolExecutor}和{@link StatisticsRunnable}
     */
    long getMinExecuteTime();
    /**
     * 任务执行最大时间,依赖于{@link top.jfunc.common.thread.monitor.adapter.MonitoredThreadPoolExecutor}和{@link StatisticsRunnable}
     */
    long getMaxExecuteTime();
    /**
	 * 任务执行超时次数,依赖于{@link top.jfunc.common.thread.monitor.adapter.MonitoredThreadPoolExecutor#setExecuteTimeout(long)}和{@link StatisticsRunnable}
	 */
	int getExecuteTimeoutCount();
	/**
	 * 执行发生异常次数
	 */
	int getExecuteExceptionCount();

	/**
     * 任务排队最小时间,依赖于{@link top.jfunc.common.thread.monitor.adapter.MonitoredThreadPoolExecutor}和{@link StatisticsRunnable}
     */
    long getMinQueueTime();
	/**
     * 任务排队最大时间,依赖于{@link top.jfunc.common.thread.monitor.adapter.MonitoredThreadPoolExecutor}和{@link StatisticsRunnable}
     */
    long getMaxQueueTime();
	/**
	 * 任务执行超时次数,依赖于{@link top.jfunc.common.thread.monitor.adapter.MonitoredThreadPoolExecutor#setQueueTimeout(long)}和{@link StatisticsRunnable}
	 */
	int getQueueTimeoutCount();

	/**
	 * 获取拒绝次数
	 */
	int getRejectedCount();


	/**
	 * 重置一些统计数据,使统计数据具备统计周期的效果
	 */
	void resetStatistic();
}


  1. 定义一种统计数据接口的实现MonitoredThreadPoolExecutor,继承自ThreadPoolExecutor,增加没有的属性,包括所属服务、名称、启动时间、任务执行时间,复写构造器传入,任务执行、排队时间相关统计可通过复写beforeExecute和afterExecute方法统计到。
package top.jfunc.common.thread.monitor.adapter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.jfunc.common.thread.monitor.ConfigurableExecutorMonitorData;
import top.jfunc.common.thread.monitor.CountedRejectedExecutionHandler;
import top.jfunc.common.thread.monitor.StatisticsRunnable;
import top.jfunc.common.thread.monitor.change.ParamChangeBean;
import top.jfunc.common.thread.monitor.change.ParamChangerUtil;
import top.jfunc.common.thread.monitor.change.ThreadPoolExecutorParamChangeAdapter;
import top.jfunc.common.thread.monitor.generator.CommonIdentifierGenerator;
import top.jfunc.common.thread.monitor.generator.IdentifierGenerator;

import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 具备监控功能的线程池,在使用j.u.c {@link ThreadPoolExecutor}的地方替换为该类即可
 */
public class MonitoredThreadPoolExecutor extends ThreadPoolExecutor implements ConfigurableExecutorMonitorData {
    private static final Logger logger = LoggerFactory.getLogger(MonitoredThreadPoolExecutor.class);
    /**
     * 所属服务
     */
    private final String service;
    /**
     * 线程池名称
     */
    private final String poolName;
    /**
     * 线程池启动时间
     */
    private final Date startTime;
    /**
     * 唯一标识
     */
    private String identifier;
    /**
     * Task execute timeout, unit (ms), just for statistics.
     * 设置了该值,才会统计执行时间
     */
    private volatile long executeTimeout = 0;

    /**
     * Task queue wait timeout, unit (ms), just for statistics.
     * 设置了该值,才会统计排队时间
     */
    private volatile long queueTimeout = 0;
    /**
     * 记录总执行时间
     */
    private final AtomicLong totalExecuteTime = new AtomicLong(0);
    /**
     * 记录一个统计周期内执行的最大时间
     */
    private volatile long maxExecuteTime = 0;
    /**
     * 记录一个统计周期内执行的最小时间
     */
    private volatile long minExecuteTime = 0;
    /**
     * Count run timeout tasks.
     */
    private final AtomicInteger executeTimeoutCount = new AtomicInteger(0);
    /**
     * Count run with Exception tasks.
     */
    private final AtomicInteger executeExceptionCount = new AtomicInteger();

    /**
     * 记录一个统计周期内排队的最大时间
     */
    private volatile long minQueueTime = 0;
    /**
     * 记录一个统计周期内排队的最大时间
     */
    private volatile long maxQueueTime = 0;
    /**
     * Count queue wait timeout tasks.
     */
    private final AtomicInteger queueTimeoutCount = new AtomicInteger();


    public MonitoredThreadPoolExecutor(int corePoolSize,
                                       int maximumPoolSize,
                                       long keepAliveTime,
                                       TimeUnit unit,
                                       BlockingQueue<Runnable> workQueue,
                                       String service,
                                       String poolName) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        this.service = service;
        this.poolName = poolName;
        this.startTime = new Date();
        this.identifier = new CommonIdentifierGenerator().getIdentifier(this);
        resetRejectedExecutionHandler();
    }

    public MonitoredThreadPoolExecutor(int corePoolSize,
                                       int maximumPoolSize,
                                       long keepAliveTime,
                                       TimeUnit unit,
                                       BlockingQueue<Runnable> workQueue,
                                       ThreadFactory threadFactory,
                                       String service,
                                       String poolName) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        this.service = service;
        this.poolName = poolName;
        this.startTime = new Date();
        this.identifier = new CommonIdentifierGenerator().getIdentifier(this);
        resetRejectedExecutionHandler();
    }

    public MonitoredThreadPoolExecutor(int corePoolSize,
                                       int maximumPoolSize,
                                       long keepAliveTime,
                                       TimeUnit unit,
                                       BlockingQueue<Runnable> workQueue,
                                       RejectedExecutionHandler handler,
                                       String service,
                                       String poolName) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        this.service = service;
        this.poolName = poolName;
        this.startTime = new Date();
        this.identifier = new CommonIdentifierGenerator().getIdentifier(this);
        resetRejectedExecutionHandler();
    }

    public MonitoredThreadPoolExecutor(int corePoolSize,
                                       int maximumPoolSize,
                                       long keepAliveTime,
                                       TimeUnit unit,
                                       BlockingQueue<Runnable> workQueue,
                                       ThreadFactory threadFactory,
                                       RejectedExecutionHandler handler,
                                       String service,
                                       String poolName) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        this.service = service;
        this.poolName = poolName;
        this.startTime = new Date();
        this.identifier = new CommonIdentifierGenerator().getIdentifier(this);
        resetRejectedExecutionHandler();
    }

    /**
     * 重置线程池的拒绝策略,可计数的
     */
    private void resetRejectedExecutionHandler() {
        setRejectedExecutionHandler(new CountedRejectedExecutionHandler(getRejectedExecutionHandler()));
    }

    @Override
    public void shutdown() {
        logger.info("{} Going to shutdown. Executed tasks: {}, Running tasks: {}, Pending tasks: {}", 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: {}", this.poolName, this.getCompletedTaskCount(), this.getActiveCount(), this.getQueue().size());
        return super.shutdownNow();
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        if (!(r instanceof StatisticsRunnable)) {
            super.beforeExecute(t, r);
            return;
        }
        StatisticsRunnable runnable = (StatisticsRunnable) r;
        long currTime = System.currentTimeMillis();
        if (executeTimeout > 0) {
            runnable.setStartTime(currTime);
        }
        if (queueTimeout > 0) {
            long queueTime = currTime - runnable.getSubmitTime();

            //更新最大等待时间
            if(queueTime > maxQueueTime){
                maxQueueTime = queueTime;
            }

            //更新最小等待时间
            if(queueTime < minQueueTime || minQueueTime == 0){
                minQueueTime = queueTime;
            }

            //看是否超时
            if (queueTime > queueTimeout) {
                queueTimeoutCount.getAndIncrement();
                //其他的可以做诸如告警
            }
        }

        super.beforeExecute(t, r);
    }
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        if (!(r instanceof StatisticsRunnable)) {
            super.afterExecute(r, t);
            return;
        }

        if (executeTimeout > 0) {
            StatisticsRunnable runnable = (StatisticsRunnable) r;
            long executeTime = System.currentTimeMillis() - runnable.getStartTime();
            //统计执行时间
            totalExecuteTime.addAndGet(executeTime);

            //更新最大执行时间
            if(executeTime > maxExecuteTime){
                maxExecuteTime = executeTime;
            }
            //更新最小执行时间
            if(executeTime < minExecuteTime || minExecuteTime == 0){
                minExecuteTime = executeTime;
            }

            //看是否超时
            if (executeTime > executeTimeout) {
                executeTimeoutCount.incrementAndGet();
                //其他的可以做诸如告警
            }

        }

        //发生异常统计
        if (null != t) {
            executeExceptionCount.incrementAndGet();
            //其他的可以做诸如告警
        }

        super.afterExecute(r, t);
    }

    @Override
    public void execute(Runnable command) {
        if(command instanceof StatisticsRunnable){
            super.execute(command);
            return;
        }
        super.execute(statisticsWrap(command));
    }

    protected Runnable statisticsWrap(Runnable command) {
        Runnable c = command;
        if(executeTimeout > 0 || queueTimeout > 0){
            c = new StatisticsRunnable(command);
        }
        return c;
    }

    @Override
    public long getTotalExecuteTime() {
        return this.totalExecuteTime.get();
    }
    @Override
    public long getMaxExecuteTime() {
        return this.maxExecuteTime;
    }

    @Override
    public long getMinExecuteTime() {
        return this.minExecuteTime;
    }

    @Override
    public int getExecuteTimeoutCount() {
        return this.executeTimeoutCount.get();
    }

    @Override
    public int getExecuteExceptionCount() {
        return executeExceptionCount.get();
    }

    @Override
    public long getMinQueueTime() {
        return this.minQueueTime;
    }

    @Override
    public long getMaxQueueTime() {
        return this.maxQueueTime;
    }

    @Override
    public int getQueueTimeoutCount() {
        return this.queueTimeoutCount.get();
    }

    @Override
    public void resetStatistic() {
        totalExecuteTime.set(0);
        maxExecuteTime = 0;
        minExecuteTime = 0;
        executeTimeoutCount.set(0);
        executeExceptionCount.set(0);

        maxQueueTime = 0;
        minQueueTime = 0;
        queueTimeoutCount.set(0);

        RejectedExecutionHandlerUtil.resetRejectedCount(getRejectedExecutionHandler());
    }

    @Override
    public Date getStartTime(){
        return this.startTime;
    }
    @Override
    public String getPoolName() {
        return this.poolName;
    }

    @Override
    public String getService() {
        return this.service;
    }

    @Override
    public String getIdentifier() {
        return this.identifier;
    }


    public MonitoredThreadPoolExecutor setIdentifierGenerator(IdentifierGenerator identifierGenerator) {
        this.identifier = identifierGenerator.getIdentifier(this);
        return this;
    }

    public MonitoredThreadPoolExecutor setExecuteTimeout(long executeTimeout) {
        this.executeTimeout = executeTimeout;
        return this;
    }

    public long getExecuteTimeout() {
        return this.executeTimeout;
    }

    public MonitoredThreadPoolExecutor setQueueTimeout(long queueTimeout) {
        this.queueTimeout = queueTimeout;
        return this;
    }

    public long getQueueTimeout() {
        return this.queueTimeout;
    }

    @Override
    public int getQueueCapacity() {
        BlockingQueue<Runnable> blockingQueue = getQueue();
        return blockingQueue.remainingCapacity() + blockingQueue.size();
    }

    @Override
    public int getQueueSize() {
        return getQueue().size();
    }

    @Override
    public String getQueueClass() {
        return getQueue().getClass().getName();
    }

    @Override
    public String getThreadFactoryClass() {
        return getThreadFactory().getClass().getName();
    }

    @Override
    public String getRejectedExecutionHandlerClass() {
        return RejectedExecutionHandlerUtil.getOriginalRejectedExecutionHandlerClass(getRejectedExecutionHandler());
    }

    @Override
    public int getRejectedCount() {
        return RejectedExecutionHandlerUtil.getRejectedCount(getRejectedExecutionHandler());
    }

    @Override
    public void onChange(ParamChangeBean bean) {
        ParamChangerUtil.paramChange(new ThreadPoolExecutorParamChangeAdapter(this), bean);
    }
}

  1. 针对某些情况我们无法直接定义线程池,即第二种方式无法实现的时候,我们可以代理线程池。定义ThreadPoolExecutorMonitoredDelegator,构造器传入ThreadPoolExecutor进行代理,增加没有的属性,包括所属服务、名称、启动时间,这种情况下无法获取到任务执行时间。
import top.jfunc.common.thread.monitor.ConfigurableExecutorMonitorData;
import top.jfunc.common.thread.monitor.CountedRejectedExecutionHandler;
import top.jfunc.common.thread.monitor.change.ParamChangeBean;
import top.jfunc.common.thread.monitor.change.ParamChangerUtil;
import top.jfunc.common.thread.monitor.change.ThreadPoolExecutorParamChangeAdapter;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 代理j.u.c原生线程池{@link ThreadPoolExecutor},附加监控相关信息
 */
public class ThreadPoolExecutorMonitoredAdapter extends AbstractThreadPoolExecutorMonitoredAdapter implements ConfigurableExecutorMonitorData {
    private final ThreadPoolExecutor delegate;

    public ThreadPoolExecutorMonitoredAdapter(ThreadPoolExecutor threadPoolExecutor, String service, String poolName) {
        super(service, poolName);
        this.delegate = threadPoolExecutor;
        this.delegate.setRejectedExecutionHandler(new CountedRejectedExecutionHandler(this.delegate.getRejectedExecutionHandler()));
    }

    @Override
    public int getActiveCount() {
        return this.delegate.getActiveCount();
    }

    @Override
    public int getMaximumPoolSize() {
        return this.delegate.getMaximumPoolSize();
    }

    @Override
    public long getCompletedTaskCount() {
        return this.delegate.getCompletedTaskCount();
    }

    @Override
    public int getPoolSize() {
        return this.delegate.getPoolSize();
    }

    @Override
    public int getCorePoolSize() {
        return this.delegate.getCorePoolSize();
    }

    @Override
    public int getLargestPoolSize() {
        return this.delegate.getLargestPoolSize();
    }

    @Override
    public long getKeepAliveTime(TimeUnit timeUnit) {
        return this.delegate.getKeepAliveTime(timeUnit);
    }

    @Override
    public boolean allowsCoreThreadTimeOut() {
        return this.delegate.allowsCoreThreadTimeOut();
    }

    @Override
    public long getTaskCount() {
        return this.delegate.getTaskCount();
    }

    @Override
    public int getQueueCapacity() {
        BlockingQueue<Runnable> blockingQueue = this.delegate.getQueue();
        return blockingQueue.remainingCapacity() + blockingQueue.size();
    }

    @Override
    public int getQueueSize() {
        return this.delegate.getQueue().size();
    }

    @Override
    public String getQueueClass() {
        return this.delegate.getQueue().getClass().getName();
    }

    @Override
    public String getThreadFactoryClass() {
        return this.delegate.getThreadFactory().getClass().getName();
    }

    @Override
    public String getRejectedExecutionHandlerClass() {
        return RejectedExecutionHandlerUtil.getOriginalRejectedExecutionHandlerClass(this.delegate.getRejectedExecutionHandler());
    }

    @Override
    public int getRejectedCount() {
        return RejectedExecutionHandlerUtil.getRejectedCount(this.delegate.getRejectedExecutionHandler());
    }

    @Override
    public void resetStatistic() {
        super.resetStatistic();
        RejectedExecutionHandlerUtil.resetRejectedCount(this.delegate.getRejectedExecutionHandler());
    }

    @Override
    public void onChange(ParamChangeBean bean) {
        ParamChangerUtil.paramChange(new ThreadPoolExecutorParamChangeAdapter(this.delegate), bean);
    }
}


  1. 定义用于上报监控信息的接口ExecutorReportService,定义两个方法,分别在线程池启动的时候调用initReport(主要用于收集线程池的参数配置,属于静态参数)和系统定时调用report(主要用于收集线程池的动态运行参数,属于动态参数)。
/**
 * 初始化线程池的时候调用,上报线程初始化相关信息
 */
public interface ExecutorReportService {
    /**
     * 线程池初始化的时候调用上报初始化信息
     * @param executorMonitorData 被监控线程池初始化信息
     */
    void initReport(ExecutorMonitorData executorMonitorData);
    /**
     * 普通上报信息,定时或者手动触发
     * @param executorMonitorData 被监控线程池监控信息
     */
    void report(ExecutorMonitorData executorMonitorData);
}
  1. 因为系统中可能有很多的上报具体实现,我们定义一个聚合的CompositeExecutorReportService,用于管理ExecutorReportService,它本身也可以看作为一个ExecutorReportService。
/**
 * 组合service,系统中可能需要多种处理
 */
public class CompositeExecutorReportService implements ExecutorReportService{
	private final List<ExecutorReportService> reportServices = new ArrayList<>();

	public CompositeExecutorReportService(List<ExecutorReportService> reportServices) {
		this.reportServices.addAll(reportServices);
	}
	public CompositeExecutorReportService(ExecutorReportService... reportServices) {
		this.reportServices.addAll(Arrays.asList(reportServices));
	}

	public CompositeExecutorReportService addServices(ExecutorReportService... reportServices){
		this.reportServices.addAll(Arrays.asList(reportServices));
		return this;
	}

	public List<ExecutorReportService> getReportServices() {
		return this.reportServices;
	}

	@Override
	public void initReport(ExecutorMonitorData executorMonitorData) {
		for (ExecutorReportService reportService : this.reportServices) {
			reportService.initReport(executorMonitorData);
		}
	}

	@Override
	public void report(ExecutorMonitorData executorMonitorData) {
		for (ExecutorReportService reportService : this.reportServices) {
			reportService.report(executorMonitorData);
		}
	}
}

  1. 定义系统的监控服务ExecutorMonitorService,构造器传入ExecutorReportService,然后启动一个定时任务每十分钟收集一次系统的线程池的统计信息。线程池通过该类的register方法进行注册。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import top.jfunc.common.thread.monitor.change.ParamChangeBean;
import top.jfunc.common.utils.MapUtil;
import top.jfunc.common.utils.ThreadFactoryBuilder;

import java.io.Closeable;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * 线程池监控定时任务,定时上报线程池相关数据
 */
public class ExecutorMonitorService implements Closeable {
    private static final Logger logger = LoggerFactory.getLogger(ExecutorMonitorService.class);
    //默认上报频率10分钟
    public static final long DEFAULT_SCHEDULER_PERIOD = 10;
    private final Map<String, ExecutorMonitorData> executorMonitorDataMap = new ConcurrentHashMap<>();
    private final ScheduledExecutorService scheduledExecutorService;

    private final CompositeExecutorReportService executorReportServices = new CompositeExecutorReportService();

    //统计数据呈现周期性,统计完成后就重置
    private boolean statisticsPeriodically = true;

    /**
     * 指定上报监控信息的频率、上报服务
     * @param initDelay 初始化延迟
     * @param schedulerPeriod 上报频率
     * @param scheduledReportServices 定时上报的时候上报服务
     */
    public ExecutorMonitorService(long initDelay, long schedulerPeriod, ExecutorReportService... scheduledReportServices) {
        //首先注册reportService,否则register线程池的时候还没有reportService,就会丢失初始化数据
        addReportService(scheduledReportServices);
        this.scheduledExecutorService = createAndInitScheduledExecutorService(initDelay, schedulerPeriod);
    }
    /**
     * 指定上报监控信息的频率默认频率、报服务
     * @param scheduledReportServices 定时上报的时候上报服务
     */
    public ExecutorMonitorService(ExecutorReportService... scheduledReportServices) {
        //首先注册reportService,否则register线程池的时候还没有reportService,就会丢失初始化数据
        addReportService(scheduledReportServices);
        this.scheduledExecutorService = createAndInitScheduledExecutorService(DEFAULT_SCHEDULER_PERIOD, DEFAULT_SCHEDULER_PERIOD);
    }
    /**
     * 指定上报监控信息的线程池、报服务
     * @param scheduledExecutorService 用于运行监控上报信息的线程池
     * @param initDelay 初始化延迟
     * @param schedulerPeriod 上报频率
     * @param scheduledReportServices 定时上报的时候上报服务
     */
    public ExecutorMonitorService(ScheduledExecutorService scheduledExecutorService, long initDelay, long schedulerPeriod, ExecutorReportService... scheduledReportServices) {
        //首先注册reportService,否则register线程池的时候还没有reportService,就会丢失初始化数据
        addReportService(scheduledReportServices);
        this.scheduledExecutorService = scheduledExecutorService;
        schedule(this.scheduledExecutorService, initDelay, schedulerPeriod);
    }

    /**
     * 指定上报监控信息的线程池、报服务
     * @param scheduledExecutorService 用于运行监控上报信息的线程池
     * @param scheduledReportServices 定时上报的时候上报服务
     */
    public ExecutorMonitorService(ScheduledExecutorService scheduledExecutorService, ExecutorReportService... scheduledReportServices) {
        //首先注册reportService,否则register线程池的时候还没有reportService,就会丢失初始化数据
        addReportService(scheduledReportServices);
        this.scheduledExecutorService = scheduledExecutorService;
        schedule(this.scheduledExecutorService, DEFAULT_SCHEDULER_PERIOD, DEFAULT_SCHEDULER_PERIOD);
    }

    /**
     * 注册监控线程池
     */
    public void register(ExecutorMonitorData... executorMonitorDataList){
        for (ExecutorMonitorData executorMonitorData : executorMonitorDataList) {
            //注册
            this.executorMonitorDataMap.put(executorMonitorData.getIdentifier(), executorMonitorData);
            //上报初始化信息
            this.executorReportServices.initReport(executorMonitorData);
        }
    }


    /**
     * 马上上报监控信息
     */
    public void reportMonitorData(){
        if(MapUtil.isEmpty(this.executorMonitorDataMap)){
            logger.warn("还没有线程池注册,放弃上报任务");
            return;
        }

        for (ExecutorMonitorData executorMonitorData : this.executorMonitorDataMap.values()) {
            try {
                this.executorReportServices.report(executorMonitorData);

                //以上执行完后才重置
                if(statisticsPeriodically){
                    executorMonitorData.resetStatistic();
                }

            } catch (Exception e) {
                //当执行失败的时候需要catch,否则后续就不会执行了
                logger.error(e.getMessage(), e);
            }
        }
    }

    /**
     * 按照指定的{@link ExecutorReportService}来上报
     */
    public void reportMonitorData(ExecutorReportService executorReportService, ExecutorReportService... otherServices){
        if(MapUtil.isEmpty(this.executorMonitorDataMap)){
            logger.warn("还没有线程池注册,放弃上报任务");
            return;
        }

        CompositeExecutorReportService compositeExecutorReportService = new CompositeExecutorReportService(executorReportService, otherServices);

        for (ExecutorMonitorData executorMonitorData : this.executorMonitorDataMap.values()) {
            compositeExecutorReportService.report(executorMonitorData);
        }
    }

    /**
     * 动态修改线程池参数
     */
    public void changeParam(ParamChangeBean bean){
        ExecutorMonitorData executorMonitorData = this.executorMonitorDataMap.get(bean.getIdentifier());
        if(null == executorMonitorData){
            logger.warn("在本机未找到待修改线程池:"+bean.getIdentifier());
            return;
        }

        if(! (executorMonitorData instanceof ConfigurableExecutorMonitorData)){
            logger.warn("放弃,该线程池不支持修改参数的:"+bean.getIdentifier());
            return;
        }

        ((ConfigurableExecutorMonitorData)executorMonitorData).onChange(bean);
    }


    public void addReportService(ExecutorReportService... reportServices){
        executorReportServices.addServices(reportServices);
    }

    public CompositeExecutorReportService getCompositeExecutorReportService() {
        return executorReportServices;
    }


    public ScheduledExecutorService getScheduledExecutorService() {
        return this.scheduledExecutorService;
    }

    public Map<String, ExecutorMonitorData> getExecutorMonitorDataMap() {
        return this.executorMonitorDataMap;
    }

    public boolean isStatisticsPeriodically() {
        return statisticsPeriodically;
    }

    public ExecutorMonitorService setStatisticsPeriodically(boolean statisticsPeriodically) {
        this.statisticsPeriodically = statisticsPeriodically;
        return this;
    }

    @Override
    public void close() throws IOException {
        this.scheduledExecutorService.shutdownNow();
        try {
            this.scheduledExecutorService.awaitTermination(10,TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            logger.warn(e.getMessage(), e);
        }
    }

    private ScheduledExecutorService createAndInitScheduledExecutorService(long initDelay, long schedulerPeriod){
        ThreadFactory threadFactory = ThreadFactoryBuilder.create()
                .setNameFormat("ExecutorMonitorService-Thread-%d")
                .setDaemon(true)
                //.setThreadFactory(Thread::new)
                .build();
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1, threadFactory);

        schedule(scheduledThreadPoolExecutor, initDelay, schedulerPeriod);

        return scheduledThreadPoolExecutor;
    }

    private void schedule(ScheduledExecutorService scheduledExecutorService, long initDelay, long schedulerPeriod) {
        scheduledExecutorService.scheduleAtFixedRate(this::reportMonitorData, initDelay, schedulerPeriod, TimeUnit.MINUTES);
    }
}


  1. 定义用于保存监控统计数据到数据库的DbExecutorReportService和打印日志的LogExecutorReportService。
public class DbExecutorReportService implements ExecutorReportService {
    public static final DbExecutorReportService service = new DbExecutorReportService();

    @Override
    public void initReport(ExecutorMonitorData executorMonitorData) {
        new ThreadpoolMonitorExecutor().setAttrs(Bean2Map.convert(ThreadPoolInitInfo.fromMonitorData(executorMonitorData))).save();
    }

    @Override
    public void report(ExecutorMonitorData executorMonitorData) {
        new ThreadpoolMonitorExecutorDetail().setAttrs(Bean2Map.convert(ThreadPoolDetailInfo.fromMonitorData(executorMonitorData))).save();
    }
}

/**
 * 将线程池监控信息json格式打印出来
 */
public class LogExecutorReportService implements ExecutorReportService {
    private static final Logger logger = LoggerFactory.getLogger(LogExecutorReportService.class);
    public static final LogExecutorReportService service = new LogExecutorReportService();

    @Override
    public void initReport(ExecutorMonitorData executorMonitorData) {
        logger.info(JSON.toJSONStringWithDateFormat(ThreadPoolInitInfo.fromMonitorData(executorMonitorData), DatetimeUtils.SDF_DATETIME));
    }

    @Override
    public void report(ExecutorMonitorData executorMonitorData) {
        logger.info(JSON.toJSONStringWithDateFormat(ThreadPoolDetailInfo.fromMonitorData(executorMonitorData), DatetimeUtils.SDF_DATETIME));
    }
}
  1. 定义线程池监控的静态数据实体ThreadPoolInitInfo和表threadpool_monitor_executor,包含所属服务、线程池名称、线程池的唯一标识(线程池一般随系统启动而启动,随系统关闭而关闭)、核心线程数、最大线程数、最大空闲时间、阻塞队列、线程工厂、拒绝策略、启动时间。
public class ThreadPoolInitInfo {
    //线程池所在服务
    private final String service;
    //线程池名称
    private final String poolName;
    //线程池唯一标识
    private final String identifier;
    //线程池核心线程数量
    private final int corePoolSize;
    //线程池中允许的最大线程数
    private final int maximumPoolSize;
    //线程最大空闲时间(毫秒)
    private final long keepAliveTime;
    //阻塞队列容量
    private final int queueCapacity;
    private final String threadFactoryClass;
    private final String blockingQueueClass;
    private final String rejectedExecutionHandlerClass;
    //线程池启动时间
    private final Date startTime;

    public ThreadPoolInitInfo(String service,
                              String poolName,
                              String identifier,
                              int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              int queueCapacity,
                              String threadFactoryClass,
                              String blockingQueueClass,
                              String rejectedExecutionHandlerClass,
                              Date startTime) {
        this.service = service;
        this.poolName = poolName;
        this.identifier = identifier;
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.keepAliveTime = keepAliveTime;
        this.queueCapacity = queueCapacity;
        this.threadFactoryClass = threadFactoryClass;
        this.blockingQueueClass = blockingQueueClass;
        this.rejectedExecutionHandlerClass = rejectedExecutionHandlerClass;
        this.startTime = startTime;
    }

    public static ThreadPoolInitInfo fromMonitorData(ExecutorMonitorData emd){
        BlockingQueue<Runnable> blockingQueue = emd.getQueue();
        return new ThreadPoolInitInfo(emd.getService(), emd.getPoolName(), emd.getIdentifier(),
                emd.getCorePoolSize(), emd.getMaximumPoolSize(),emd.getKeepAliveTime(TimeUnit.MILLISECONDS),
                blockingQueue.remainingCapacity()+ blockingQueue.size(),
                emd.getThreadFactory().getClass().getName(),
                blockingQueue.getClass().getName(),
                emd.getRejectedExecutionHandler().getClass().getName(),
                emd.getStartTime());
    }
}
  1. 定义线程池监控的动态数据实体ThreadPoolDetailInfo和表threadpool_monitor_executor_detail,所属服务、线程池名称、线程池的唯一标识(线程池一般随系统启动而启动,随系统关闭而关闭)、核心线程数、当前线程数、历史最大线程、最大线程数、当前活跃线程数、最大空闲时间、当前任务数、已完成数量、任务执行总时间、阻塞队列、线程工厂、拒绝策略、启动时间。
package top.jfunc.common.thread.monitor.bean;

import top.jfunc.common.thread.monitor.ExecutorMonitorData;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.concurrent.TimeUnit;

public class ThreadPoolDetailInfo {
    //线程池所在服务
    private final String service;
    //线程池名称
    private final String poolName;
    //线程池唯一标识
    private final String identifier;
    //当前线程池大小
    private final int poolSize;
    //线程池核心线程数量
    private final int corePoolSize;
    //线程池生命周期中最大线程数量
    private final int largestPoolSize;
    //线程池中允许的最大线程数
    private final int maximumPoolSize;
    //线程池完成的任务数目
    private final long completedTaskCount;
    //线程池中当前活跃个数
    private final int activeCount;
    //线程池当前的任务个数
    private final long taskCount;
    //线程最大空闲时间(毫秒)
    private final long keepAliveTime;
    //是否允许核心线程空闲回收,0和1,数字方便存储
    private final int allowsCoreThreadTimeOut;
    //当前活跃线程的占比
    private final int activePercent;
    //任务队列容量(阻塞队列)
    private final int queueCapacity;
    //当前队列中任务的数量
    private final int queueSize;
    //线程池中任务平均执行时长
    private final long avgExecuteTime;
    //最长执行时间
    private final long maxExecuteTime;
    //最短执行时间
    private final long minExecuteTime;
    //线程池中执行超时次数
    private final long executeTimeoutCount;
    //线程池中执行发生异常次数
    private final long executeExceptionCount;
    //最长等待时间
    private final long maxQueueTime;
    //最短等待时间
    private final long minQueueTime;
    //线程池中排队超时次数
    private final long queueTimeoutCount;
    //拒绝次数
    private final int rejectedCount;
    //线程池启动时间
    private final Date startTime;
    //统计时间
    private final Date createTime;

    public ThreadPoolDetailInfo(String service,
                                String poolName,
                                String identifier,
                                int poolSize,
                                int corePoolSize,
                                int largestPoolSize,
                                int maximumPoolSize,
                                long completedTaskCount,
                                int activeCount,
                                long taskCount,
                                long keepAliveTime,
                                int allowsCoreThreadTimeOut,
                                int activePercent,
                                int queueCapacity,
                                int queueSize,
                                long avgExecuteTime,
                                long maxExecuteTime,
                                long minExecuteTime,
                                long executeTimeoutCount,
                                long executeExceptionCount,
                                long maxQueueTime,
                                long minQueueTime,
                                long queueTimeoutCount,
                                int rejectedCount,
                                Date startTime,
                                Date createTime) {
        this.service = service;
        this.poolName = poolName;
        this.identifier = identifier;
        this.poolSize = poolSize;
        this.corePoolSize = corePoolSize;
        this.largestPoolSize = largestPoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.completedTaskCount = completedTaskCount;
        this.activeCount = activeCount;
        this.taskCount = taskCount;
        this.keepAliveTime = keepAliveTime;
        this.allowsCoreThreadTimeOut = allowsCoreThreadTimeOut;
        this.activePercent = activePercent;
        this.queueCapacity = queueCapacity;
        this.queueSize = queueSize;
        this.avgExecuteTime = avgExecuteTime;
        this.maxExecuteTime = maxExecuteTime;
        this.minExecuteTime = minExecuteTime;
        this.executeTimeoutCount = executeTimeoutCount;
        this.executeExceptionCount = executeExceptionCount;
        this.maxQueueTime = maxQueueTime;
        this.minQueueTime = minQueueTime;
        this.queueTimeoutCount = queueTimeoutCount;
        this.rejectedCount = rejectedCount;
        this.startTime = startTime;
        this.createTime = createTime;
    }

    public static ThreadPoolDetailInfo fromMonitorData(ExecutorMonitorData emd){
        BigDecimal activeCount = new BigDecimal(emd.getActiveCount());
        BigDecimal maximumPoolSize = new BigDecimal(emd.getMaximumPoolSize());
        BigDecimal result = activeCount.divide(maximumPoolSize, 2, RoundingMode.HALF_UP);
        int activePercent = new Double(result.doubleValue() * 100).intValue();

        //总时间/总完成任务数
        long avgExecuteTime = emd.getCompletedTaskCount() == 0L ? 0L : emd.getTotalExecuteTime() / emd.getCompletedTaskCount();

        return new ThreadPoolDetailInfo(emd.getService(), emd.getPoolName(), emd.getIdentifier(),
                emd.getPoolSize(),emd.getCorePoolSize(),emd.getLargestPoolSize(),emd.getMaximumPoolSize(),
                emd.getCompletedTaskCount(),emd.getActiveCount(),emd.getTaskCount(),emd.getKeepAliveTime(TimeUnit.MILLISECONDS),
                emd.allowsCoreThreadTimeOut() ? 1 : 0, activePercent,
                emd.getQueueCapacity(),emd.getQueueSize(),
                avgExecuteTime,emd.getMaxExecuteTime(), emd.getMinExecuteTime(),emd.getExecuteTimeoutCount(),emd.getExecuteExceptionCount(),
                emd.getMaxQueueTime(), emd.getMinQueueTime(), emd.getQueueTimeoutCount(),
                emd.getRejectedCount(),emd.getStartTime(),new Date());
    }
DROP TABLE IF EXISTS `threadpool_monitor_executor`;
CREATE TABLE `threadpool_monitor_executor` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `service` varchar(64) NOT NULL COMMENT '线程池所在服务',
  `poolName` varchar(64) NOT NULL COMMENT '线程池名称',
  `identifier` varchar(128) NOT NULL COMMENT '线程池的唯一标识',
  `corePoolSize` int(11) NOT NULL COMMENT '核心线程数',
  `maximumPoolSize` int(11) NOT NULL COMMENT '最大线程数',
  `keepAliveTime` bigint(20) NOT NULL COMMENT '最大空闲时间(ms)',
  `queueCapacity` int(11) NOT NULL COMMENT '阻塞队列容量',
  `threadFactoryClass` varchar(255) DEFAULT NULL,
  `blockingQueueClass` varchar(255) DEFAULT NULL,
  `rejectedExecutionHandlerClass` varchar(255) DEFAULT NULL,
  `startTime` datetime DEFAULT NULL COMMENT '线程池启动时间',
  PRIMARY KEY (`id`),
  KEY `idx_time` (`startTime`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for threadpool_monitor_executor_detail
-- ----------------------------
CREATE TABLE `threadpool_monitor_executor_detail` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `service` varchar(64) NOT NULL COMMENT '线程池所在服务',
  `poolName` varchar(64) NOT NULL COMMENT '线程池名称',
  `identifier` varchar(128) NOT NULL COMMENT '线程池的唯一标识',
  `poolSize` int(11) NOT NULL COMMENT '当前线程池大小',
  `corePoolSize` int(11) NOT NULL COMMENT '核心线程数量',
  `largestPoolSize` int(11) NOT NULL COMMENT '到达过的最大线程数量',
  `keepAliveTime` bigint(20) NOT NULL COMMENT '最大空闲时间(ms)',
  `allowsCoreThreadTimeOut` int(1) NOT NULL DEFAULT '0' COMMENT '是否允许核心线程空闲回收',
  `maximumPoolSize` int(11) NOT NULL COMMENT '最大线程数量',
  `completedTaskCount` int(11) NOT NULL COMMENT '完成的任务数量',
  `activeCount` int(11) NOT NULL COMMENT '活跃线程数',
  `taskCount` int(11) NOT NULL COMMENT '任务数量',
  `activePercent` int(11) NOT NULL COMMENT '活跃占比',
  `queueCapacity` int(11) NOT NULL COMMENT '阻塞队列容量',
  `queueSize` int(11) NOT NULL COMMENT '阻塞队列任务数量',
  `avgExecuteTime` bigint(20) NOT NULL COMMENT '线程池中任务平均执行时长(ms)',
  `maxExecuteTime` bigint(20) NOT NULL DEFAULT '0' COMMENT '最大执行时间,周期性统计',
  `minExecuteTime` bigint(20) NOT NULL DEFAULT '0' COMMENT '最小执行时间,周期性统计',
  `executeTimeoutCount` int(11) NOT NULL DEFAULT '0' COMMENT '执行超时次数',
  `executeExceptionCount` int(11) NOT NULL DEFAULT '0' COMMENT '执行异常次数,即抛出异常次数',
  `maxQueueTime` bigint(20) NOT NULL DEFAULT '0' COMMENT '最大排队时间,周期性统计',
  `minQueueTime` bigint(20) NOT NULL DEFAULT '0' COMMENT '最小排队时间,周期性统计',
  `queueTimeoutCount` int(11) NOT NULL DEFAULT '0' COMMENT '排队超时次数',
  `rejectedCount` int(11) NOT NULL DEFAULT '0' COMMENT '拒绝次数',
  `createTime` datetime NOT NULL COMMENT '统计时间',
  PRIMARY KEY (`id`),
  KEY `idx_time_service_name` (`createTime`,`service`,`poolName`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT DEFAULT CHARSET=utf8mb4;



  1. 开发页面用于展示线程池的静态参数和动态参数,动态参数展示中有一个比较特别的参数。因为相同的线程池可能因为重启唯一标识identifier不一样,但是所属服务service和名称poolName不会变。
  2. 以如下定义的线程池和任务统计数据图表展示如下
public class ExecutorMonitorServiceHolder {
	public static final ExecutorMonitorService service = new ExecutorMonitorService(2,2,new LogExecutorReportService(),new DbExecutorReportService());

	static {
		ThreadFactory threadFactory = ThreadFactoryBuilder.create()
				.setNameFormat("Test-Monitor-Thread-%d")
				.setDaemon(true)
				//.setThreadFactory(Thread::new)
				.build();
		ThreadPoolExecutor.AbortPolicy policy = new ThreadPoolExecutor.AbortPolicy();
		MonitoredThreadPoolExecutor executor = new MonitoredThreadPoolExecutor(4,
				10,
				60,
				TimeUnit.SECONDS,
				new LinkedBlockingQueue<>(20),
				threadFactory,
				policy,
				"Rest", IpUtil.getLocalIp()+":"+ SystemConfig.config.port+":TestMonitorExecutor")
				.setExecuteTimeout(1000).setQueueTimeout(1000);
		ExecutorMonitorServiceHolder.service.register( executor);

		new Thread(()->{
			for (int i=0;i<10000000;i++){
				final int j = i;
				executor.execute(()->{
					if(j % 10 == 0){
						throw new RuntimeException();
					}
					ThreadUtil.sleeps(RandomUtil.randomInt(10));
				});
				ThreadUtil.sleeps(2);
			}
		}).start();
	}
}

线程池线程监控
线程池任务监控
线程池队列监控
线程池任务执行时间监控
线程池异常监控
其他

(二)、线程池动态修改参数

  1. 定义修改接口
/**
 * 可修改参数的线程池接口
 */
public interface ConfigurableExecutorMonitorData extends ExecutorMonitorData{
	/**
	 * 修改线程池参数
	 * @param bean 待修改的参数值
	 */
	void onChange(ParamChangeBean bean);
}

实现该类的就需要实现该方法,将新参数设置进线程池
2. MonitoredThreadPoolExecutor中的修改

    @Override
    public void onChange(ParamChangeBean bean) {
        ParamChangerUtil.paramChange(new ThreadPoolExecutorParamChangeAdapter(this), bean);
    }



import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * j.u.c {@link ThreadPoolExecutor}适配器
 */
public class ThreadPoolExecutorParamChangeAdapter implements ParamChangeable{
	private final ThreadPoolExecutor delegate;

	public ThreadPoolExecutorParamChangeAdapter(ThreadPoolExecutor threadPoolExecutor) {
		this.delegate = threadPoolExecutor;
	}

	@Override
	public int getCorePoolSize() {
		return this.delegate.getCorePoolSize();
	}

	@Override
	public void setCorePoolSize(int corePoolSize) {
		this.delegate.setCorePoolSize(corePoolSize);
	}

	@Override
	public int getMaximumPoolSize() {
		return this.delegate.getMaximumPoolSize();
	}

	@Override
	public void setMaximumPoolSize(int maximumPoolSize) {
		this.delegate.setMaximumPoolSize(maximumPoolSize);
	}

	@Override
	public long getKeepAliveTime(TimeUnit timeUnit) {
		return this.delegate.getKeepAliveTime(timeUnit);
	}

	@Override
	public void setKeepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
		this.delegate.setKeepAliveTime(keepAliveTime, timeUnit);
	}

	@Override
	public boolean allowsCoreThreadTimeOut() {
		return this.delegate.allowsCoreThreadTimeOut();
	}

	@Override
	public void allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
		this.delegate.allowCoreThreadTimeOut(allowCoreThreadTimeOut);
	}

	@Override
	public void setCapacity(int queueCapacity) {
		//队列容量
		BlockingQueue<Runnable> blockingQueue = this.delegate.getQueue();
		if(blockingQueue instanceof ResizableCapacityLinkedBlockingQueue){
			int capacity = ((ResizableCapacityLinkedBlockingQueue<Runnable>) blockingQueue).getCapacity();
			if(capacity != queueCapacity){
				((ResizableCapacityLinkedBlockingQueue<?>)blockingQueue).setCapacity(queueCapacity);
			}
		}
	}
}




import java.util.concurrent.TimeUnit;

public class ParamChangerUtil {
	private ParamChangerUtil(){}

	public static void paramChange(ParamChangeable paramChangeable, ParamChangeBean bean){
		//核心线程数
		int corePoolSize = bean.getCorePoolSize();
		if (corePoolSize != paramChangeable.getCorePoolSize()){
			paramChangeable.setCorePoolSize(corePoolSize);
		}

		//最大线程数
		int maximumPoolSize = bean.getMaximumPoolSize();
		if (maximumPoolSize != paramChangeable.getMaximumPoolSize()){
			paramChangeable.setMaximumPoolSize(maximumPoolSize);
		}

		//最大空闲时间
		long keepAliveTime = bean.getKeepAliveTime();
		if (keepAliveTime != paramChangeable.getKeepAliveTime(TimeUnit.MILLISECONDS)){
			paramChangeable.setKeepAliveTime(keepAliveTime, TimeUnit.MILLISECONDS);
		}

		//是否允许核心线程空闲回收
		int allowCoreThreadTimeOut = bean.getAllowCoreThreadTimeOut();
		paramChangeable.allowCoreThreadTimeOut(1 == allowCoreThreadTimeOut);

		//队列容量
		paramChangeable.setCapacity(bean.getQueueCapacity());
	}
}

以后适配其他线程池照此即可
3. 而调用方法,在ExecutorMonitorService#changeParam中,一般有三种通知方法,收到通知后调用此方法修改。因为一般滴都需要考虑集群部署的情况。
1) 利用redis的pubsub机制
2)利用nginx的mirror机制
3)有配置中心的利用配置中心的动态修改参数通知

    /**
     * 动态修改线程池参数
     */
    public void changeParam(ParamChangeBean bean){
        ExecutorMonitorData executorMonitorData = this.executorMonitorDataMap.get(bean.getIdentifier());
        if(null == executorMonitorData){
            logger.warn("在本机未找到待修改线程池:"+bean.getIdentifier());
            return;
        }

        if(! (executorMonitorData instanceof ConfigurableExecutorMonitorData)){
            logger.warn("放弃,该线程池不支持修改参数的:"+bean.getIdentifier());
            return;
        }

        ((ConfigurableExecutorMonitorData)executorMonitorData).onChange(bean);
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值