StopWatch在单个文件的单个方法中确时还蛮好用的,但跨多个文件,多个方法的同一线程内调试就有明显的不舒服。一是要建立ThreadLocal共享StopWatch的实例。二是StopWatch的start和stop必须形成闭合。在方法嵌套的场景。比如要查看大方法执行时间,还要查看大方法里面的某个调用的执行时间。这就没法做到了。3就是StopWatch以纳秒为单位,阅读不舒服(非高并发网站,没那么高的要求,毫秒即可),因此,做了这款调试工作。只记录线程某些栈节点的抵达时间。形成一个时间轴。最后打印这个时间轴的相邻时间差即可。调试中,只要确定费时的代码在哪个小区间,一般有经验的话能很快定位到问题代码。
效果如下图:
代码实现:
有需要的可以拿去美化下
public class RunnerAnalyzer { private final static ThreadLocal<List<RunnerInfo>> CONTAINER = new ThreadLocal<>(); public static void start(String nodeName) { List<RunnerInfo> runnerInfos = CONTAINER.get(); if (null == runnerInfos) { CONTAINER.set(new ArrayList<>()); } List<RunnerInfo> container = CONTAINER.get(); container.add(new RunnerInfo(nodeName)); CONTAINER.set(container); } public static void clear() { CONTAINER.remove(); } public static void prettyPrint(long moreThanTime) { RunnerAnalyzer.start("耗时记录结束"); List<RunnerInfo> runnerInfos = CONTAINER.get(); if (null == runnerInfos) { clear(); return; } int size = runnerInfos.size(); int lastIndex = size - 1; RunnerInfo first = runnerInfos.get(0); RunnerInfo last = runnerInfos.get(lastIndex); long totalTime = last.getTime() - first.getTime(); // 只打印超过某一时间的,免得压力测试的时候疯狂刷 if (totalTime < moreThanTime) { clear(); return; } StringBuilder sb = new StringBuilder(); sb.append("--------------------------------------------- "); String totalMessage = "总耗时" + totalTime + " "; sb.append(totalMessage); String title = "抵达时间 耗时 占比 节点名称 "; sb.append(title); for (int i = 0; i < size; i++) { RunnerInfo runnerInfo = runnerInfos.get(i); String showTimeName = runnerInfo.getShowTime() + " "; sb.append(showTimeName); if (i != 0) { RunnerInfo lastNode = runnerInfos.get(i - 1); long lastNodeTime = lastNode.getTime(); long during = runnerInfo.getTime() - lastNodeTime; String duringStr = during + " "; sb.append(duringStr); String rate = ZYNumberUtils.rate(during, totalTime) + " "; sb.append(rate); } else { sb.append("0 "); sb.append(" "); } String nodeName = runnerInfo.getNodeName() + " "; sb.append(nodeName); } sb.append("--------------------------------------------- "); System.out.println(sb.toString()); clear(); } }
public class RunnerInfo { private String nodeName; private long time; private String showTime; public RunnerInfo(String nodeName) { this.nodeName = nodeName; Date date = new Date(); this.time = date.getTime(); this.showTime = ZYDateUtils.formart(date, "yyyy-MM-dd HH:mm:ss:SSS"); } }