场景:我们在系统运行中,需要监控某个代码段的运行时间,我们完全可以使用currentTimeMillis来做,但是做起来比较麻烦,尤其是需要阶段监控的时候,那么这个工具就出现啦~~~

先说下想要实现的功能:1.能够对代码段进行运行时间的监控,比如代码行a->代码行b的运行时间。2.能够监控代码行嵌套的运行时间监控,比如a->b->c->d中a->d和b->c的运行时间监控(类似括号一样,形成配对的方式)。3.能够在运行范围内的jvm一些指标的监控,比如内存使用量等。

/**
* 性能相关的调试工具,支持,线程正式场景,做运行时间的profile,运行性能监控(不建议线上使用,因为需要开启监控线程)
* 该工具不会抛出任何异常
* @author Administrator
* @version $Id: ProfileUtils.java, v 0.1 2016年9月5日 下午11:02:45 Administrator Exp $
*/
public class Profiler { /** debug模式 */
// private static volatile boolean debug = false; private final static String LOG_TEMPLATE = "[messag=%s][startTime=%s][endTime=%s][durationTime=%sms][processors=%s][memUse=%s]";
private final static String SIMPLE_LOG_TEMPLATE = "[durationTime=%sms][message=%s]";
private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(
"yyyy/MM/dd HH:mm:ss"); /** profile日志,建议运行中别做修改,否则有些配置会导致残留线程 */
private static ThreadLocal<ProfileConfig> configHolder = new ThreadLocal<ProfileConfig>() {
protected ProfileConfig initialValue() {
return new ProfileConfig(
false, false,
0);
};
}; /** 开始monitor的时间 */
private static ThreadLocal<Stack<MonitorResource>> resStackHolder = new ThreadLocal<Stack<MonitorResource>>() {
protected java.util.Stack<MonitorResource> initialValue() {
return new Stack<MonitorResource>();
};
}; /** 监控线程 */
private static ThreadLocal<MonitorThread> monitorThreadHolder = new ThreadLocal<MonitorThread>(); /**
* 开始monitor
*/
public static void enter(Object msgObj) {
try {
Stack<MonitorResource> monitorResStack = resStackHolder.get();
monitorResStack.push(new MonitorResource(msgObj, System.currentTimeMillis()));
ProfileConfig config = configHolder.get();
//开启监控线程
if (config.isUseMonitorThread()) {
if (monitorThreadHolder.get() != null) {
killThread();
}
MonitorThread monitorThread = new MonitorThread(getCurrentMonitorRes(), config);
monitorThreadHolder.set(monitorThread);
monitorThread.start();
}
} catch (Throwable e) {
// if (debug) {
// e.printStackTrace();
// }
return;
}
} /**
* 结束monitor
* @return
*/
public static MonitorResource release() {
try {
Stack<MonitorResource> monitorResStack = resStackHolder.get();
MonitorResource monitorResource = getCurrentMonitorRes();
monitorResource.setEndTime(System.currentTimeMillis());
ProfileConfig config = configHolder.get();
//监控线程关闭
if (config.isUseMonitorThread()) {
killThread();
}
return monitorResStack.pop();
} catch (Throwable e) {
// if (debug) {
// e.printStackTrace();
// }
return new MonitorResource(e.getMessage(), 0);
}
} /**
* 使用新的messageObj替换原来的
* @param messageObj
* @return
*/
public static MonitorResource release(Object messageObj) {
MonitorResource monitorResource = release();
monitorResource.setMessageObj(messageObj);
return monitorResource;
} /**
* 结束monitor并且打印日志
* @param logger
* @return
*/
public static MonitorResource releaseAndLog(Logger logger, Object messageObj) {
MonitorResource resource = release(messageObj);
LoggerUtils.info(logger, resource);
return resource;
} /**
* 结束monitor并且打印日志
* @param logger
* @return
*/
public static MonitorResource releaseAndLog(Logger logger) {
MonitorResource resource = release();
LoggerUtils.info(logger, resource);
return resource;
} /**
* 设置profile配置
* @param config
*/
public static void setProfileConfig(ProfileConfig config) {
configHolder.set(config);
} /**
* Setter method for property <tt>debug</tt>.
*
* @param debug value to be assigned to property debug
*/
// public static void setDebug(boolean debug) {
// Profiler.debug = debug;
// } /**
* 移除监控线程
*/
private static void killThread() {
try {
MonitorThread futureTask = monitorThreadHolder.get();
monitorThreadHolder.remove();
futureTask.interrupt();
} catch (Throwable e) {
// ignore
// if (debug) {
// e.printStackTrace();
// }
}
} /**
* 获取当前的monitorRes
* @return
*/
public static MonitorResource getCurrentMonitorRes() {
try {
Stack<MonitorResource> resStack = resStackHolder.get();
return resStack.get(resStack.size() - 1);
} catch (Exception e) {
// if (debug) {
// e.printStackTrace();
// }
return new MonitorResource(e.getMessage(), 0);
}
} /**
* 资源使用情况,比如cpu最大使用量等。
* @author Administrator
* @version $Id: Profile.java, v 0.1 2016年9月5日 下午11:38:39 Administrator Exp $
*/
public static class MonitorResource { /** 当前资源的标志 */
private Object messageObj = null; private long startTime = 0; private long endTime = 0; private int processorNums = 0; private List<Long> memUse = Lists.newArrayList(); /**
* @param messageObj
* @param startTime
*/
public MonitorResource(Object messageObj, long startTime) {
super();
this.messageObj = messageObj;
this.startTime = startTime;
} /**
* Setter method for property <tt>messageObj</tt>.
*
* @param messageObj value to be assigned to property messageObj
*/
public void setMessageObj(Object messageObj) {
this.messageObj = messageObj;
} public String getMemUse() {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < memUse.size(); i++) {
stringBuilder.append(memUse.get(i) / 1024L + "K");
if (i != memUse.size() - 1) {
stringBuilder.append(",");
}
}
return stringBuilder.toString();
} /**
* 获取整个profile堆栈
* @return
*/
public Stack<MonitorResource> getMonitorResStack() {
return resStackHolder.get();
} /**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return configHolder.get().isUseSimpleLogTemplate()
? (String.format(SIMPLE_LOG_TEMPLATE, endTime - startTime, messageObj))
: (String.format(LOG_TEMPLATE, messageObj, DATE_FORMAT.format(new Date(startTime)),
DATE_FORMAT.format(new Date(endTime)), endTime - startTime, processorNums,
getMemUse()));
} /**
* 获取运行时间
* @return
*/
public long getDurTime() {
return endTime - startTime;
} public void putMemUse(long l) {
memUse.add(l);
} /**
* Setter method for property <tt>endTime</tt>.
*
* @param endTime value to be assigned to property endTime
*/
public void setEndTime(long endTime) {
this.endTime = endTime;
} /**
* Getter method for property <tt>messageObj</tt>.
*
* @return property value of messageObj
*/
public Object getMessageObj() {
return messageObj;
} /**
* Setter method for property <tt>processorNums</tt>.
*
* @param processorNums value to be assigned to property processorNums
*/
public void setProcessorNums(int processorNums) {
this.processorNums = processorNums;
} } public static class ProfileConfig {
private boolean useSimpleLogTemplate = false;
private boolean useMonitorThread = false;
private int monitorCollectDurTime = 500; /**
* @param useSimpleLogTemplate
* @param useMonitorThread
* @param monitorCollectDurTime
*/
public ProfileConfig(boolean useSimpleLogTemplate, boolean useMonitorThread,
int monitorCollectDurTime) {
super();
this.useSimpleLogTemplate = useSimpleLogTemplate;
this.useMonitorThread = useMonitorThread;
this.monitorCollectDurTime = monitorCollectDurTime;
} /**
* Getter method for property <tt>useSimpleLogTemplate</tt>.
*
* @return property value of useSimpleLogTemplate
*/
public boolean isUseSimpleLogTemplate() {
return useSimpleLogTemplate;
} /**
* Setter method for property <tt>useSimpleLogTemplate</tt>.
*
* @param useSimpleLogTemplate value to be assigned to property useSimpleLogTemplate
*/
public void setUseSimpleLogTemplate(boolean useSimpleLogTemplate) {
this.useSimpleLogTemplate = useSimpleLogTemplate;
} /**
* Getter method for property <tt>useMonitorThread</tt>.
*
* @return property value of useMonitorThread
*/
public boolean isUseMonitorThread() {
return useMonitorThread;
} /**
* Setter method for property <tt>useMonitorThread</tt>.
*
* @param useMonitorThread value to be assigned to property useMonitorThread
*/
public void setUseMonitorThread(boolean useMonitorThread) {
this.useMonitorThread = useMonitorThread;
} /**
* Getter method for property <tt>monitorCollectDurTime</tt>.
*
* @return property value of monitorCollectDurTime
*/
public int getMonitorCollectDurTime() {
return monitorCollectDurTime;
} /**
* Setter method for property <tt>monitorCollectDurTime</tt>.
*
* @param monitorCollectDurTime value to be assigned to property monitorCollectDurTime
*/
public void setMonitorCollectDurTime(int monitorCollectDurTime) {
this.monitorCollectDurTime = monitorCollectDurTime;
} } private static class MonitorThread extends Thread { private static final AtomicLong threadCount = new AtomicLong(); private MonitorResource monitorResource; private final ProfileConfig config; /**
*
*/
public MonitorThread(MonitorResource resource, ProfileConfig config) {
monitorResource = resource;
setName("monitor-thread-" + threadCount.getAndIncrement());
setDaemon(true);
this.config = config;
} /**
* @see java.lang.Thread#run()
*/
@Override
public void run() {
monitorResource.setProcessorNums(Runtime.getRuntime().availableProcessors());
while (true) {
monitorResource.putMemUse(
Runtime.getRuntime().maxMemory() - Runtime.getRuntime().freeMemory()); try {
Thread.sleep(config.getMonitorCollectDurTime());
} catch (InterruptedException e) {
// if (debug) {
// e.printStackTrace();
// }
return;
}
}
}
}
}

可以看到,我们有个监控资源的概念,每个阶段都对应一个监控资源,比如a->d和b->c都对应了一个监控资源。从实现上,每次进入监控的时候,会生成一个监控资源,并且记录当前时间,并且把该监控资源压栈。同时,还会启动一个监控线程,将jvm的状态不断写入该监控资源中,所以针对a->d和b->c都生成了自己的监控线程,并且吧jvm状态写入自己的监控资源中。  当release的时候,会kill掉监控线程,并且把监控资源出栈。

根据上面的设计可以看到,该工具的使用需要注意下面的问题:

1.如果不启用监控线程,那么可以用于线上的场景。

2.如果启用了监控线程,那么只适合debug分析的场景,因为如果是线上,当监控的代码块并发量大起来的时候,会以1:1的比例创建监控线程,这个时候会有风险。

3.启用监控线程的场景比较适合于,并发量较小(创建的监控线程少),但是执行时间长的场景。这个时候可以对代码块进行执行分析。

一个java的Profile工具的更多相关文章

  1. 推荐一个 Java 实体映射工具 MapStruct

    声明: 1.DO(业务实体对象),DTO(数据传输对象). 2.我的代码中用到了 Lombok ,不了解的可以自行了解一下,了解的忽略这条就好. 在一个成熟的工程中,尤其是现在的分布式系统中,应用与应 ...

  2. 利用Google开源Java容器化工具Jib构建镜像

    转载:https://blog.csdn.net/u012562943/article/details/80995373 一.前言 容器的出现让Java开发人员比以往任何时候都更接近“编写一次,到处运 ...

  3. Java反编译工具Luyten介绍

    比较精准的一个java反编译工具,笔者有时候用jd-gui反编译不出来的class用luyten都可以反编译出来. 官方网站:https://github.com/deathmarine/Luyten ...

  4. java 邮件发送工具类【来源网络自己已经实际应用】

    最近在做一个Java发送邮件的工具类,现在分享一下完整的代码 首先需要java邮件的包javax.mail-1.5.4.jar 之前因为链接给错了,很不好意思,现在重新发一次. 包在这里可以下载htt ...

  5. 我的Android进阶之旅------>Java文件大小转换工具类 (B,KB,MB,GB,TB,PB之间的大小转换)

    Java文件大小转换工具类 (B,KB,MB,GB,TB,PB之间的大小转换) 有时候要做出如下所示的展示文件大小的效果时候,需要对文件大小进行转换,然后再进行相关的代码逻辑编写. 下面是一个Java ...

  6. WEKA,一个开源java的数据挖掘工具

    开始研究WEKA,一个开源java的数据挖掘工具. HS沉寂这么多天,谁知道偏偏在我申请离职的时候给我安排了个任务,哎,无语. 于是,今天看了一天的Weka. 主要是看了HS提供的三个文章(E文,在g ...

  7. java 写一个JSON解析的工具类

    上面是一个标准的json的响应内容截图,第一个红圈”per_page”是一个json对象,我们可以根据”per_page”来找到对应值是3,而第二个红圈“data”是一个JSON数组,而不是对象,不能 ...

  8. 八、jdk工具之JvisualVM、JvisualVM之二--Java程序性能分析工具Java VisualVM

    目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...

  9. 超好用的自带火焰图的 Java 性能分析工具 Async-profiler 了解一下

    如果你经常遇到 Java 线上性能问题束手无策,看着线上服务 CPU 飙升一筹莫展,发现内存不断泄露满脸茫然.别慌,这里有一款低开销.自带火焰图.让你大呼好用的 Java 性能分析工具 - async ...

随机推荐

  1. CSS3初学篇章_7(布局/浏览器默认样式重置)

    CSS布局说到布局,就不得不提布局的核心<div>标签,它与其它标签一样,也是一个XHTML所支持的标签,专门用于布局设计的容器标签.在css布局方式中,div 是这种布局方式的核心对象, ...

  2. 20145205 《Java程序设计》实验报告五:Java网络编程及安全

    20145205 <Java程序设计>实验报告五:Java网络编程及安全 实验要求 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.客户端中输入明文,利用DES算法加密,D ...

  3. POJ 1274 The Perfect Stall、HDU 2063 过山车(最大流做二分匹配)

    The Perfect Stall Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24081   Accepted: 106 ...

  4. NorthWind 数据库整体关系

    http://blog.csdn.net/bergn/article/details/1502150 今天看到一张非常有用的图,说明有关Northwind数据库整体关系的图,以前一直在用,但是没有一个 ...

  5. java并发容器类

    本文主要介绍java并发容器相关实现类,collections节点下接口方法介绍. Queue Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是Blocking ...

  6. 【Git学习笔记】撤销修改

    工作区下的.git文件夹其实是Git的版本库,Git的版本库里存了很多东西,其中最重要的就是称为 stage 的暂存区,还有Git为我们自动创建的第一个分支 master ,以及指向master的一个 ...

  7. iOS开发中获取WiFi相关信息

    iOS 开发中难免会遇到很多与网络方面的判断,这里做个汇总,大多可能是与WiFi相关的. 1.Ping域名.Ping某IP 有 时候可能会遇到ping 某个域名或者ip通不通,再做下一步操作.这里的p ...

  8. PCB上过孔via钻孔的直径如何设置 是任意的吗 谈谈PCB钻孔工艺及规格

    PCB上过孔via钻孔的直径如何设置,是不是可以随便填入一个直径尺寸就行了?比如我的走线宽度是6mil,那我的via过孔直径也设置为6mil,节约布线空间岂不是更好?这样的设计板厂是否都能按照设计规格 ...

  9. 快速原型设计工具-Axure RP的介绍及简单使用(生产初期向客户展示设计产品的原型-也就是展示产品)

    啧啧~~ 给大家介绍一款超棒的原型设计工具--美国Axure Software Solution公司旗舰产品Axure RP 这款工具通俗的说呢,就是在项目整体需求考察后对整体设计一个简要性概括!设计 ...

  10. Magento的基本架构解析

    Magento的基本架构解析 magento 是在Zend框架基础上建立起来的,这点保证了代码的安全性及稳定性.选择Zend的原因有很多,但是最基本的是因为 zend框架提供了面向对象的代码库并且有很 ...