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 JMX
can monitor and manage applications. JMX
The most common scenario is to monitor the Java
basic information and the operation of the program, any Java
program can open JMX
and use JConsole
or Visual VM
preview
JMX architecture
A total of three layers, distribution layers, proxy layer, the device layerdistribution 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 MBean
more, so here only Standard MBean
, using the Standard MBean
need to meet certain rules, rules are as follows:
- Define an interface, the interface name must be
XXXXMBean
of format, you must be toMBean
end - If the interface
XXXXMBean
, the interface implementation class must beMBean
, otherwise the program will report an error - By interface
get
andset
represents monitoring index is readable, writable method. For examplegetXXX()
the abstract method,XXX
is to monitor the indicator,getXXX()
indicatesXXX
performance-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 JMX
and after the thread pool, to write a JMX
monitor 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
poolName
indicate which a thread pool, and rewritebeforeExecute
,afterExecute
,terminated
method, atbeforeExecute
the time of performing the thread pool recording method, theafterExecute
calculation 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
MBean
in fact, not a single entity but rather an interface class, which defines the indicators monitoredpublic 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
MBean
class that implements:ThreadPoolParam.java
the definition of a static MBean, so the interface implementation class must meet the requirement thatxxxMBean
, 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 classHtmlAdaptor.start()
OpenHTTP
connected view monitoring tasks
After starting the program opens
http://localhost:8082/
as shown below:
Click test-pool-1
undertype=threadPoolParam
Refresh the thread pool by acquiring the latest monitoring indicators test-pool-1
and type=threadPoolParam
these properties are in ObjectName
property values defined in
to sum up
Use JMX
monitoring the thread pool is just JMX
a 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]