二日前、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
れたスレッドプールを示し、書き換えbeforeExecute
、afterExecute
、terminated
で、方法beforeExecute
、スレッドプールの記録方法を行う際afterExecute
の実行消費のスレッドの算出方法最大時間、かかる最小消費、平均時間がかかります。スレッドプールのスレッドを生成するためのメソッドをオーバーライド、スレッド割り当てられた名前の生成 -
定義
MBean
:ThreadPoolParamMBean.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-1
下type=threadPoolParam
最新のモニタリング指標を取得することで、スレッドプールを更新test-pool-1
し、type=threadPoolParam
これらのプロパティはしているObjectName
中で定義されたプロパティ値
概要
使用するJMX
スレッドプールだけである監視JMX
機能、この資料では、彼らの知識を適用し、JMXスレッドプールの詳細は、他の材料で見つけることができます。間違った記事なら、私を修正してください
最終添付ファイル:プロジェクトコードは、歓迎フォークでスター、[私は計画がに焦点を当ててきたスターそれ]