Spring 工具类的 Stopwatch 计时的简单使用
我们在计算某个代码块或某个方法的具体执行时间/速度时,一般方法是获取执行前后的时间戳,并计算差值得到结果。但这种方式并不优雅,在同时计算多个代码块或一些方法的执行时间/速度时,由于可读性较差,可能引起错读而写出办法,写多了也比较烦人。本文将使用 Spring-Framework 的 StopWatch 类,优雅且便利的实现相同效果。
1 为什么要使用 StopWatch
接下来将使用以下两个方法作对比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
public class GetTime { public static void main(String[] args) throws Exception { useCurrentTimeMillis(); useStopWatchOne(); }
private static void useStopWatchOne() throws Exception { StopWatch stopWatchOne = new StopWatch(); StopWatch stopWatchTwo = new StopWatch(); stopWatchOne.start("外层代码块"); stopWatchTwo.start("内层代码块a"); Thread.sleep(1000); stopWatchTwo.stop(); System.out.println(stopWatchTwo.getLastTaskName() + "执行时间:" + stopWatchTwo.getLastTaskTimeMillis()); stopWatchTwo.start("内层代码块b"); Thread.sleep(2000); stopWatchTwo.stop(); System.out.println(stopWatchTwo.getLastTaskName() + "执行时间:" + stopWatchTwo.getLastTaskTimeMillis()); Thread.sleep(4000); stopWatchOne.stop(); System.out.println(stopWatchOne.getLastTaskName() + "执行时间:" + stopWatchOne.getTotalTimeMillis()); }
private static void useCurrentTimeMillis() throws Exception { long startTimeOne = System.currentTimeMillis(); long startTimeTwo = System.currentTimeMillis(); Thread.sleep(1000); long stopTimeTwo = System.currentTimeMillis(); System.out.println("内层代码块a执行时间:" + (stopTimeTwo - startTimeTwo)); Thread.sleep(2000); long startTimeThree = System.currentTimeMillis(); Thread.sleep(3000); long stopTimeThree = System.currentTimeMillis(); System.out.println("内层代码块b执行时间:" + (stopTimeThree - startTimeThree)); Thread.sleep(4000); long stopTimeOne = System.currentTimeMillis(); System.out.println("外层代码块执行时间:" + (stopTimeOne - startTimeOne)); } }
|
执行结果如下:
1 2 3 4 5 6 7 8
| 内层代码块a执行时间:1006 内层代码块b执行时间:3010 外层代码块执行时间:10037 内层代码块a执行时间:1000 内层代码块b执行时间:1999 外层代码块执行时间:7010
Process finished with exit code 0
|
两者对比,可以看出 StopWatch 的便利性和可读性。StopWatch 实现计算代码时间的流程如下:
1 2 3 4
| 先 new 一个 StopWatch 对象 再 start 开始计时 然后 stop 停止计时 最后通过 stopwatch.getLastTaskTimeMillis() 得出时间差
|
如果换成使用 System.currentTimeMillis() 呢?先得声明好几个 long 类型的局部变量,然后相互之间去减,烦人不说,稍微粗心一点(尤其是 CV 大法)时,很容易搞错,代码可读性也较差。
2 StopWatch 的其他用法
除了使用 stopwatch.getTotalTimeMillis() 方法获取局部(最近一次)的时间差之外,还可以使用 stopwatch.getTotalTimeSeconds() 来获取总的时间耗时,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private static void useStopWatchTwo() throws Exception { StopWatch stopWatchOne = new StopWatch(); stopWatchOne.start("代码块a"); Thread.sleep(1000); stopWatchOne.stop(); System.out.println(stopWatchOne.getLastTaskName() + "执行时间:" + stopWatchOne.getLastTaskTimeMillis()); stopWatchOne.start("代码块b"); Thread.sleep(2000); stopWatchOne.stop(); System.out.println(stopWatchOne.getLastTaskName() + "执行时间:" + stopWatchOne.getLastTaskTimeMillis()); stopWatchOne.start("代码块c"); Thread.sleep(4000); stopWatchOne.stop(); System.out.println(stopWatchOne.getLastTaskName() + "执行时间:" + stopWatchOne.getLastTaskTimeMillis()); System.out.println("代码总执行时间:" + stopWatchOne.getTotalTimeMillis()); }
|
执行结果:
1 2 3 4 5 6
| 代码块a执行时间:1012 代码块b执行时间:2011 代码块c执行时间:4009 代码总执行时间:7033
Process finished with exit code 0
|
除此之外,StopWatch 还提供了stopwatch.prettyPrint() 方法来更优雅的打印结果:
1 2 3 4 5 6 7 8 9 10 11 12 13
| private static void useStopWatchThree() throws Exception { StopWatch stopWatchOne = new StopWatch(); stopWatchOne.start("代码块a"); Thread.sleep(1000); stopWatchOne.stop(); stopWatchOne.start("代码块b"); Thread.sleep(2000); stopWatchOne.stop(); stopWatchOne.start("代码块c"); Thread.sleep(4000); stopWatchOne.stop(); System.out.println(stopWatchOne.prettyPrint()); }
|
执行结果如下:
1 2 3 4 5 6 7 8 9 10
| StopWatch '': running time = 7019842800 ns --------------------------------------------- ns % Task name --------------------------------------------- 1004075800 014% 代码块a 2007161500 029% 代码块b 4008605500 057% 代码块c
Process finished with exit code 0
|
非常优雅且清晰的数据,不仅有耗时,还有占比,甚至还有任务名。其余的打印或用法还有很多,例如
1 2 3 4 5 6 7
| getTotalTimeSeconds() 获取总耗时秒,同时也有获取毫秒的方法 prettyPrint() 优雅的格式打印结果,表格形式 shortSummary() 返回简短的总耗时描述 getTaskCount() 返回统计时间任务的数量 getTaskName() 返回最后一个任务对象的名称 taskCount() 累计执行的计时任务数量 还可以调用 suspend() 方法暂停计时、resume() 方法恢复计时、reset() 重新计时。
|
最后附上本文所写源代码:StopWatch的简单使用