JMX視覚的な監視スレッドプール

二日前、JMXは、通常のタスクとステータス情報を監視して読んで、会社コードを確認するには、単語JMXはおなじみ感じるので、彼らは少しにアクセスするために移動し、デモは、スレッドプールを監視書きました

この記事を読んだことによって、あなたは学ぶことができます:

  • JMXはじめに
  • スレッドプール
  • JMX監視アプリケーションのスレッドプール

JMXとは何ですか

JMXの概要

JMX(Java Management Extensions)、使用して監視および管理フレームワークは、JMXアプリケーションを監視および管理することができます。JMX最も一般的なシナリオを監視することでJava基本的な情報やプログラムの動作を、任意のJavaプログラムを開くことができますJMXし、使用JConsoleまたはVisual VMプレビュー

JMXアーキテクチャ

三層、分配層、プロキシ層、デバイス層の総
分配層 :異なるプロトコルに基づく各種の運用管理インタフェースのプロキシレイヤを定義し、ビューの監視指標の簡単な方法であることができる HTTP 接続、 RMI 接続、 SNMP 接続
層プロキシは :管理 MBean によって MBean 登録剤層の実装 MBean 管理、登録に加えて MBean 、またに登録することができる Adapter アプリケーション層におけるプロキシは、一般に MBeanService
、デバイス層 :監視インデックス抽象クラスは、以下に分けることができます。

  • 標準のMBean
  • ダイナミックMBeanの
  • 公開MBean
  • モデルのMBean
  • MXBeanの

アプリケーションは、一般的に使用Standard MBeanだけなので、ここでは、より多くのをStandard MBean使用して、Standard MBean特定のルールを満たすために必要性を次のように、ルールは以下のとおりです。

  • インターフェイスを定義し、インタフェース名でなければなりませんXXXXMBean形式で、あなたでなければなりませんMBean終了
  • インターフェースは場合はXXXXMBean、インタフェースの実装クラスでなければなりませんMBean、そうでないプログラムはエラーを報告します
  • インタフェースによってget、およびset、監視指標が読み取り可能、書き込み可能な方法を表します。例えば、getXXX()抽象メソッドは、XXXインジケータを監視することで、getXXX()示しXXX性能読み取り可能な、setXXX()方法は、監視インデックス書き込み可能なことを示しています
  • パラメータと戻り値の型は、単純な参照型(例えばすることができString、)と基本データ型の戻り値は、カスタムタイプを選択することができる場合は、カスタム・タイプではありませんMXBean

スレッドプールブリーフ

スレッドプールは、スレッド管理ツールである、あなたは、応答率を改善し、スレッドの管理性を向上させるために、スレッドプールを使用してリソースの消費量を削減するためのスレッドを再利用することができます。プール・システム内のスレッドの数が多い場合は、エラーの位置決めを容易にするために、スレッドプールを監視する必要があります。パラメータは、スレッドプールのパラメータが提供するスレッドプールを経由して監視することができ、以下のとおりです。

方法 意味
getActiveCount ミッションのプール内のスレッドの数
getCompletedTaskCount スレッドプール完了したタスクの数
getCorePoolSize スレッドプール内のスレッドのコア数
getLargestPoolSize スレッドプールは、スレッドの最大数を作成するために使用します
getMaximumPoolSize スレッドプール内のスレッドの最大数
getPoolSize スレッドプール内のスレッドの現在の数
getTaskCount あなたがスレッドプールを実行する必要があるタスクの数

アプリケーション

入門JMXスレッドプールと後に、書くためJMXのモニタスレッドプールをDemo、それができない紙の上

  • カスタムスレッドプールの監視カテゴリ: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;
            }
        }
    }
    复制代码

    スレッドプールからスレッドプールを継承することによって定義され、コンストラクタに接合さpoolNameれたスレッドプールを示し、書き換えbeforeExecuteafterExecuteterminatedで、方法beforeExecute、スレッドプールの記録方法を行う際afterExecuteの実行消費のスレッドの算出方法最大時間、かかる最小消費、平均時間がかかります。スレッドプールのスレッドを生成するためのメソッドをオーバーライド、スレッド割り当てられた名前の生成

  • 定義MBeanThreadPoolParamMBean.java
    MBean監視対象の指標を定義する事実ではなく、単一のエンティティではなく、インタフェースクラスを

    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();
    }
    复制代码
  • 定義MBean実装するクラス:ThreadPoolParam.java
    静的のMBeanの定義を、そのインタフェースの実装クラスは、要件を満たす必要がありxxxMBean、実装クラスのためにxxx

    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();
        }
    }
    复制代码

    監視パラメータのインデックスは、スレッドプールによって得られます

  • テストカテゴリ: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();
        }
    }
    复制代码

    説明:

    • MBeanServerUtil.registerMBean()クラスの監視をサインアップ
    • HtmlAdaptor.start()オープンHTTP接続ビューの監視タスク

    プログラムを起動した後開き、http://localhost:8082/下図のように:

クリックしてtest-pool-1type=threadPoolParam

最新のモニタリング指標を取得することで、スレッドプールを更新test-pool-1し、type=threadPoolParamこれらのプロパティはしているObjectName中で定義されたプロパティ値

概要

使用するJMXスレッドプールだけである監視JMX機能、この資料では、彼らの知識を適用し、JMXスレッドプールの詳細は、他の材料で見つけることができます。間違った記事なら、私を修正してください

最終添付ファイル:プロジェクトコードは、歓迎フォークスター、[私は計画がに焦点を当ててきたスターそれ]

おすすめ

転載: juejin.im/post/5dae82646fb9a04df901a08d