转载请注明出处::https://blog.csdn.net/jevonsCSDN/article/details/83118799 【Jevons’Blog】
本文是关于实时监控方法耗时的工具,不依赖任何插件,丢进去就可以用。本工具类采用ThreadLocal实现多线程分化管理监控信息,不用担心结果的准确性。写的比较潦草,由于本人只是用于测试,懒得优化了,有兴趣的可以改改。
方便用于测试,不建议投入生产。
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
/**
* 耗时监控类(测试用,不建议在生产环境跑)
* 严格按照每个start方法由一个end方法结束(缺失end块会导致内存泄漏)
* @author Zhang Haowen
*/
public class CostMonitorUtils {
private static final Map<PatternType, Vector<SimpleDateFormatSub>> TYPE_MAP = new HashMap<PatternType, Vector<SimpleDateFormatSub>>();
private static final int maxSize = 0x32;//格式池最大值:50
private static boolean outputTolog = true;//[true]:日志打印到文件|[false]:日志不打印到文件
private static String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
private static final String LOG_PATH = "E:\\CostMonitor";
static {
for(PatternType patternType: PatternType.values()){
TYPE_MAP.put(patternType, new Vector<SimpleDateFormatSub>());
}
}
//耗时记录器
private static ThreadLocal<List<Long>> timeMillsRecord = new ThreadLocal<List<Long>>(){
@Override
protected List<Long> initialValue() {
return new ArrayList<Long>();
};
};
//监控文件名、行号记录器
private static ThreadLocal<List<String>> lineRecord = new ThreadLocal<List<String>>(){
@Override
protected List<String> initialValue() {
return new ArrayList<String>();
};
};
private static Long start(String message,String endLineInfo){
SimpleDateFormatSub formator = getFormator(PatternType.YEAR_TO_SECOND);
String finalMessage="";
message=rebuildMessage(message);
long startTimeMillis = System.currentTimeMillis();
//记录开始监控时间
List<Long> list = timeMillsRecord.get();
list.add(startTimeMillis);
//记录开始监控文件名、行数
List<String> lineRecordList = lineRecord.get();
lineRecordList.add(endLineInfo);
if(!message.equals("")){
endLineInfo= rebuildMessage(endLineInfo);
finalMessage=">>>>"+message+endLineInfo+"开始耗时监控---> "+ formator.format(new Date());
System.out.println(finalMessage);
}
free(formator);
outputToLogFile(finalMessage+"\r\n");
return startTimeMillis;
}
/**
* 开始监控
* @param message
* @return
*/
public static Long start(String message){
return start(message,getLineInfo(2));
}
/**
* 调整message格式
* @param message
* @return
*/
private static String rebuildMessage(String message){
if(message!=null&&!message.equals("")){
message =" "+message+" ";
}else{
message ="";
}
return message;
}
/**
* 开始耗时监控
* @return 返回开始时间戳
*/
public static Long start(){
return start(null,getLineInfo(2));
}
/**
* 结束耗时监控
* @return 返回结束时间戳
*/
public static Long end(){
return end(null,getLineInfo(2));
}
/**
* 结束耗时监控
* @param message
* @return
*/
public static Long end(String message) {
return end(message, getLineInfo(2));
}
/**
* 结束耗时监控
* @param message
* @return 返回结束时间戳
* @throws Exception
*/
private static Long end(String message,String endLineInfo){
String finalMessage="";
message=rebuildMessage(message);
long endTimeMillis = System.currentTimeMillis();
List<Long> list = timeMillsRecord.get();
List<String> lineRecordList = lineRecord.get();
if(list.size()>0){
Long startTimeMillis = list.remove(list.size()-1);
String lineInfo = rebuildMessage(lineRecordList.remove(lineRecordList.size()-1)+" → "+endLineInfo);
//格式化毫秒
String costTime =formatMS(endTimeMillis-startTimeMillis,false);
finalMessage=">>>>"+lineInfo+"Cost Time:"+costTime+message;
System.out.println(finalMessage);
}else{
clearCache();
finalMessage="The CostMonitor hasn't started yet.";
System.out.println(finalMessage);
}
outputToLogFile(finalMessage+"\r\n");
return endTimeMillis;
}
/**
* 获取行号信息
* @param index
* @return
*/
public static String getLineInfo(int index) {
StackTraceElement ste3 = new Throwable().getStackTrace()[index];
return (ste3.getFileName() + ": Line " + ste3.getLineNumber());
}
/**
* 输出到日志文件
* @param value
* @throws IOException
*/
private static void outputToLogFile(String value) {
if(!outputTolog){
return ;
}
if(value==null||value.trim().equals("")) return ;
FileOutputStream out = null;
try {
out = new FileOutputStream(LOG_PATH+currentDate+".log",true);
out.write(value.getBytes("UTF-8"));
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
out.flush();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 清除缓存
* @throws Exception
*/
public static void clearCache(){
if(timeMillsRecord.get()!=null&&timeMillsRecord.get().size()!=0){
outputToLogFile("CostMonitorUtils tried to clear cache denied!One or more START block is not ended!\r\n");
return ;
}
timeMillsRecord.remove();
lineRecord.remove();
}
/**
* 将毫秒转为时分秒格式
* @param millisecond
* @param chinese 是否启用中文
* @return
*/
private static String formatMS(long millisecond,boolean chinese){
String h = chinese?"小时":"h";
String m = chinese?"分":"m";
String s = chinese?"秒":"s";
String ms = chinese?"毫秒":"ms";
if(millisecond>=3600000){
return millisecond/3600000+h+(millisecond%3600000)/60000+m+(millisecond%60000)/1000+s+(millisecond%1000)+ms;
}else if(millisecond>=60000&&millisecond<3600000){
return millisecond/60000+m+(millisecond%60000)/1000+s+(millisecond%1000)+ms;
}else if(millisecond>=1000&&millisecond<60000){
return millisecond/1000+s+ (millisecond%1000)+ms;
}else{
return millisecond+ms;
}
}
public static synchronized SimpleDateFormatSub getFormator(PatternType patternType){
if(TYPE_MAP.get(patternType).size()==0){
return new SimpleDateFormatSub(patternType);
}else{
return TYPE_MAP.get(patternType).remove(0);
}
}
public static synchronized SimpleDateFormatSub getFormator(){
return getFormator(PatternType.values()[0]);//default
}
public static synchronized void free(SimpleDateFormatSub sdf){
if(TYPE_MAP.get(sdf.getPatternType()).size()<maxSize){
TYPE_MAP.get(sdf.getPatternType()).add(sdf);
}
}
public static class SimpleDateFormatSub extends SimpleDateFormat{
private static final long serialVersionUID = 1L;
private PatternType patternType;
public SimpleDateFormatSub(PatternType patternType) {
super.applyPattern(patternType.toString());;
this.setPatternType(patternType);
}
public PatternType getPatternType() {
return patternType;
}
public void setPatternType(PatternType patternType) {
this.patternType = patternType;
}
}
public enum PatternType{
YEAR_TO_DAY ("yyyy-MM-dd"),
YEAR_TO_SECOND ("yyyy-MM-dd HH:mm:ss");
private String patternValue;
private PatternType(String patternValue) {
this.patternValue=patternValue;
}
@Override
public String toString() {
return this.patternValue;
}
}
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
new Thread( new Runnable() {
public void run() {
CostMonitorUtils.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
CostMonitorUtils.end();
}
}).start();
}
}
}