CostMonitorUtils耗时监控工具类(线程安全)

转载请注明出处: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();
		}
		
	}
	
}

发布了17 篇原创文章 · 获赞 4 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览