JMX visual monitoring thread pool

Two days ago to see the company code reading with JMX monitoring regular tasks and status information, the word JMX feel familiar so they go to access a bit, and wrote Demo monitor thread pool

By reading this article you will learn:

  • JMX Introduction
  • Thread Pools
  • JMX monitoring application thread pool

What is JMX

Introduction to JMX

JMX(Java Management Extensions), Monitoring and management framework, through the use JMXcan monitor and manage applications. JMXThe most common scenario is to monitor the Javabasic information and the operation of the program, any Javaprogram can open JMXand use JConsoleor Visual VMpreview

JMX architecture

A total of three layers, distribution layers, proxy layer, the device layer
distribution layer : Defines the proxy layer for various operations management interface based on different protocols, is a simple way of monitoring indicators of view, can be HTTP connected, RMI the connection , SNMP connection
proxy layer : managing MBean , by the MBean registered agent layer implementation MBean management, in addition to registration MBean , may also register with Adapter the proxy in the application layer is generally MBeanService
the device layer : monitoring index abstract classes can be divided into the following:

  • Standard MBean
  • Dynamic MBean
  • Open MBean
  • Model MBean
  • MXBean

Applications generally use Standard MBeanmore, so here only Standard MBean, using the Standard MBeanneed to meet certain rules, rules are as follows:

  • Define an interface, the interface name must be XXXXMBeanof format, you must be to MBeanend
  • If the interface XXXXMBean, the interface implementation class must be MBean, otherwise the program will report an error
  • By interface getand setrepresents monitoring index is readable, writable method. For example getXXX()the abstract method, XXXis to monitor the indicator, getXXX()indicates XXXperformance-readable, setXXX()the method indicates that the monitoring index writable
  • Parameter and return type can be a simple reference type (e.g. String) and basic data types, are not custom type, if the return value may be selected custom typeMXBean

Thread Pool brief

Thread pool is a thread management tool, you can reuse threads to reduce resource consumption by using a thread pool to improve the response rate and improve the manageability of threads. If a large number of threads in the pool system, it is necessary to monitor the thread pool to facilitate positioning of error. Parameters can be monitored via the thread pool provided by the thread pool parameters are as follows:

method meaning
getActiveCount The number of threads in the pool on a mission
getCompletedTaskCount The number of tasks completed thread pool
getCorePoolSize The core number of threads in the thread pool
getLargestPoolSize Thread pool used to creating the maximum number of threads
getMaximumPoolSize The maximum number of threads in the thread pool
getPoolSize The current number of threads in the thread pool
getTaskCount The number of tasks you need to perform thread pool

application

Introduction to JMXand after the thread pool, to write a JMXmonitor thread pool Demo, it can not on paper

  • Custom thread pool monitoring categories:ThreadPoolMonitor.java

    public class ThreadPoolMonitor extends ThreadPoolExecutor {
        private final Logger logger = LoggerFactory.getLogger(getClass());
    
        /**
         * ActiveCount
         * */
        int ac = 0;
    
        /**
         * 当前所有线程消耗的时间
         * */
        private AtomicLong totalCostTime = new AtomicLong();
    
        /**
         * 当前执行的线程总数
         * */
        private AtomicLong totalTasks = new AtomicLong();
    
        /**
         * 线程池名称
         */
        private String poolName;
    
        /**
         * 最短 执行时间
         * */
        private long minCostTime;
    
        /**
         * 最长执行时间
         * */
        private long maxCostTime;
    
    
        /**
         * 保存任务开始执行的时间
         */
        private ThreadLocal<Long> startTime = new ThreadLocal<>();
    
        public ThreadPoolMonitor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                               TimeUnit unit, BlockingQueue<Runnable> workQueue, String poolName) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
              Executors.defaultThreadFactory(), poolName);
        }
    
        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.poolName = poolName;
        }
    
        public static ExecutorService newFixedThreadPool(int nThreads, String poolName) {
            return new ThreadPoolMonitor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), poolName);
        }
    
        public static ExecutorService newCachedThreadPool(String poolName) {
            return new ThreadPoolMonitor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>(), poolName);
        }
    
        public static ExecutorService newSingleThreadExecutor(String poolName) {
            return new ThreadPoolMonitor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), poolName);
        }
    
        /**
         * 线程池延迟关闭时(等待线程池里的任务都执行完毕),统计线程池情况
         */
        @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) {
            startTime.set(System.currentTimeMillis());
        }
    
        /**
         * 任务执行之后,计算任务结束时间
         */
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            long costTime = System.currentTimeMillis() - startTime.get();
            startTime.remove();  //删除,避免占用太多内存
            //设置最大最小执行时间
            maxCostTime = maxCostTime > costTime ? maxCostTime : costTime;
            if (totalTasks.get() == 0) {
                minCostTime = costTime;
            }
            minCostTime = minCostTime < costTime ? minCostTime : costTime;
            totalCostTime.addAndGet(costTime);
            totalTasks.incrementAndGet();
    
            logger.info("{}-pool-monitor: " +
                          "Duration: {} ms, PoolSize: {}, CorePoolSize: {}, ActiveCount: {}, " +
                          "Completed: {}, Task: {}, Queue: {}, LargestPoolSize: {}, " +
                          "MaximumPoolSize: {},  KeepAliveTime: {}, isShutdown: {}, isTerminated: {}",
                    this.poolName,
                    costTime, this.getPoolSize(), this.getCorePoolSize(), super.getActiveCount(),
                    this.getCompletedTaskCount(), this.getTaskCount(), this.getQueue().size(), this.getLargestPoolSize(),
                    this.getMaximumPoolSize(), this.getKeepAliveTime(TimeUnit.MILLISECONDS), this.isShutdown(), this.isTerminated());
        }
    
        public int getAc() {
            return ac;
        }
    
        /**
         * 线程平均耗时
         *
         * @return
         * */
        public float getAverageCostTime() {
            return totalCostTime.get() / totalTasks.get();
        }
    
        /**
         * 线程最大耗时
         * */
        public long getMaxCostTime() {
            return maxCostTime;
        }
    
        /**
         * 线程最小耗时
         * */
        public long getMinCostTime() {
            return minCostTime;
        }
    
        /**
         * 生成线程池所用的线程,改写了线程池默认的线程工厂
         */
        static class EventThreadFactory implements ThreadFactory {
            private static final AtomicInteger poolNumber = new AtomicInteger(1);
            private final ThreadGroup group;
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            private final String namePrefix;
    
            /**
             * 初始化线程工厂
             *
             * @param poolName 线程池名称
             */
            EventThreadFactory(String poolName) {
                SecurityManager s = System.getSecurityManager();
                group = Objects.nonNull(s) ? s.getThreadGroup() :   Thread.currentThread().getThreadGroup();
                namePrefix = poolName + "-pool-" + poolNumber.getAndIncrement() + "-thread-";
            }
    
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
                if (t.isDaemon())
                    t.setDaemon(false);
                if (t.getPriority() != Thread.NORM_PRIORITY)
                    t.setPriority(Thread.NORM_PRIORITY);
                return t;
            }
        }
    }
    复制代码

    Defined by inheriting the thread pool from a thread pool, and joined in the constructor poolNameindicate which a thread pool, and rewrite beforeExecute, afterExecute, terminatedmethod, at beforeExecutethe time of performing the thread pool recording method, the afterExecutecalculation method of a thread of execution consumption , the maximum time consuming, consuming the minimum, average time-consuming. Overriding methods to generate the thread pool thread, the thread assigned name generation

  • Define a MBean: ThreadPoolParamMBean.java
    MBeanin fact, not a single entity but rather an interface class, which defines the indicators monitored

    public interface ThreadPoolParamMBean {
        /**
         * 线程池中正在执行任务的线程数量
         *
         * @return
         */
        int getActiveCount();
    
        /**
         * 线程池已完成的任务数量
         *
         * @return
         */
        long getCompletedTaskCount();
    
        /**
         * 线程池的核心线程数量
         *
         * @return
         */
        int getCorePoolSize();
    
        /**
         * 线程池曾经创建过的最大线程数量
         *
         * @return
         */
        int getLargestPoolSize();
    
        /**
         * 线程池的最大线程数量
         *
         * @return
         */
        int getMaximumPoolSize();
    
        /**
         * 线程池当前的线程数量
         *
         * @return
         */
        int getPoolSize();
    
        /**
         * 线程池需要执行的任务数量
         *
         * @return
         */
        long getTaskCount();
    
        /**
         * 线程最大耗时
         *
         * @return
         * */
        long getMaxCostTime();
    
        /**
         * 线程最小耗时
         *
         * @return
         * */
        long getMinCostTime();
    
        /**
         * 线程平均耗时
         *
         * @return
         * */
        float getAverageCostTime();
    }
    复制代码
  • Define a MBeanclass that implements: ThreadPoolParam.java
    the definition of a static MBean, so the interface implementation class must meet the requirement that xxxMBean, for the implementation classxxx

    public class ThreadPoolParam implements ThreadPoolParamMBean  {
        private ThreadPoolMonitor threadPoolMonitor;
    
        public ThreadPoolParam(ExecutorService es) {
            this.threadPoolMonitor = (ThreadPoolMonitor) es;
        }
    
        /**
         * 线程池中正在执行任务的线程数量
         *
         * @return
         */
        @Override
        public int getActiveCount() {
            return threadPoolMonitor.getAc();
        }
    
        /**
         * 线程池已完成的任务数量
         *
         * @return
         */
        @Override
        public long getCompletedTaskCount() {
            return threadPoolMonitor.getCompletedTaskCount();
        }
    
        /**
         * 线程池的核心线程数量
         *
         * @return
         */
        @Override
        public int getCorePoolSize() {
            return threadPoolMonitor.getCorePoolSize();
        }
    
        /**
         * 线程池曾经创建过的最大线程数量
         *
         * @return
         */
        @Override
        public int getLargestPoolSize() {
            return threadPoolMonitor.getLargestPoolSize();
        }
    
        /**
         * 线程池的最大线程数量
         *
         * @return
         */
        @Override
        public int getMaximumPoolSize() {
            return threadPoolMonitor.getMaximumPoolSize();
        }
    
        /**
         * 线程池当前的线程数量
         *
         * @return
         */
        @Override
        public int getPoolSize() {
            return threadPoolMonitor.getPoolSize();
        }
    
        /**
         * 线程池需要执行的任务数量
         *
         * @return
         */
        @Override
        public long getTaskCount() {
            return threadPoolMonitor.getTaskCount();
        }
    
        /**
         * 线程最大耗时
         *
         * @return
         * */
        @Override
        public long getMaxCostTime() {
            return threadPoolMonitor.getMaxCostTime();
        }
    
        /**
         * 线程最小耗时
         *
         * @return
         * */
        @Override
        public long getMinCostTime() {
            return threadPoolMonitor.getMinCostTime();
        }
    
        /**
         * 线程平均耗时
         *
         * @return
         * */
        @Override
        public float getAverageCostTime() {
            return threadPoolMonitor.getAverageCostTime();
        }
    }
    复制代码

    Monitoring parameter index is obtained by a thread pool

  • Test categories:Test.java

    public class Test {
        private static Random random = new Random();
        public static void main(String[] args) throws MalformedObjectNameException,  InterruptedException {
            ExecutorService es1 = ThreadPoolMonitor.newCachedThreadPool("test-pool-1");
            ThreadPoolParam threadPoolParam1 = new ThreadPoolParam(es1);
    
            ExecutorService es2 = ThreadPoolMonitor.newCachedThreadPool("test-pool-2");
            ThreadPoolParam threadPoolParam2 = new ThreadPoolParam(es2);
    
            MBeanServerUtil.registerMBean(threadPoolParam1, new ObjectName("test-pool-1:type=threadPoolParam"));
            MBeanServerUtil.registerMBean(threadPoolParam2, new ObjectName("test-pool-2:type=threadPoolParam"));
    
            //http连接的方式查看监控任务
            HtmlAdaptor.start();
    
            executeTask(es1);
            executeTask(es2);
            Thread.sleep(1000 * 60 * 60);
        }
    
        private static void executeTask(ExecutorService es) {
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    int temp = i;
                    es.submit(() -> {
                        //随机睡眠时间
                        try {
                            Thread.sleep(random.nextInt(60) * 1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(temp);
                    });
                }
            }).start();
        }
    }
    复制代码

    Description:

    • MBeanServerUtil.registerMBean()Sign up monitoring of class
    • HtmlAdaptor.start()Open HTTPconnected view monitoring tasks

    After starting the program opens http://localhost:8082/as shown below:

Click test-pool-1undertype=threadPoolParam

Refresh the thread pool by acquiring the latest monitoring indicators test-pool-1and type=threadPoolParamthese properties are in ObjectNameproperty values defined in

to sum up

Use JMXmonitoring the thread pool is just JMXa function, this article only apply their knowledge, and more about JMX thread pool can be found in other materials. Please correct me if wrong article

Last Attachment: project code , welcomed the fork with the star , [I have a plan focused on the star it]

Guess you like

Origin juejin.im/post/5dae82646fb9a04df901a08d