当前位置: 首页 > 科技观察

还在用newDate计算任务执行时间?强烈推荐使用这个API!

时间:2023-03-21 21:45:52 科技观察

在实践中,我们经常需要记录一个任务的执行时间,这是评估代码质量、评估代码性能、排查业务执行问题的重要操作。那么,如何获取和计算任务执行所花费的时间呢?通过newDate获取时间进行转换?或者有更好的解决方案吗?这篇文章会给你答案。通常获取耗时任务的方法是获取耗时任务。最简单的方法是打印当前时间和任务开始时间之间的差值。示例代码如下:@TestpublicvoidtestElapsedTimes()throwsInterruptedException{longstartTime=newDate().getTime();//dosomethingThread.sleep(1000);System.out.println("执行耗时:"+(newDate().getTime()-startTime)+"ms");}上面的方法实现简单,逻辑也比较直观。但是如果执行了大量的测试,测试中有不同的代码逻辑块,那么需要改的地方就更多了。改进上述代码中,如果IDE安装了代码检查工具,会提示使用System.currentTimeMillis()获取时间,而不是newDate().getTime()。改造后的实现代码如下:@TestpublicvoidtestElapsedTimes1()throwsInterruptedException{longstartTime=System.currentTimeMillis();//dosomethingThread.sleep(1000);System.out.println("执行耗时:"+(System.currentTimeMillis()-startTime)+"ms");}这种场景下(不需要获取更多Date相关信息),也推荐使用System.currentTimeMillis()获取时间戳。至于为什么,看Date的源码实现就好了。Date的构造方法:publicDate(){this(System.currentTimeMillis());}Date在构造时本质上是先获取System.currentTimeMillis(),再初始化其他信息。由于我们只需要时间戳,因此无需构建Date对象。从性能的角度来说,能优化就优化。以上两种Spring的StopWatch方法虽然在性能和写法上有所不同,但本质是一样的。下面说一下Spring提供的StopWatch类。它不仅可以实现上述功能,还可以控制类似任务的执行时间,即封装了一个记录开始时间和结束时间的Java类。先通过StopWatch类实现以上功能:@TestpublicvoidtestStopWatch()throwsInterruptedException{StopWatchsw=newStopWatch();sw.start("开始执行业务");//dosomethingThread.sleep(1000);sw.stop();System.out.println(sw.getTotalTimeMillis());}创建一个StopWatch对象,然后调用它的start和stop方法区分执行任务间隔,通过getTotalTimeMillis()方法得到总耗时。乍一看,代码似乎比之前的方法多了很多,并没有什么优势!让我们看一个更复杂的例子:@TestublicvoidtestStopWatch1()throwsInterruptedException{StopWatchsw=newStopWatch();sw.start("起床");Thread.sleep(1000);sw.stop();sw.start("washing");Thread.sleep(2000);sw.stop();sw.start("锁门");Thread.sleep(500);sw.stop();System.out.println(sw.prettyPrint());System.out.println(sw.getTotalTimeMillis());System.out.println(sw.getLastTaskName());System.out.println(sw.getLastTaskInfo());System.out.println(sw.getTaskCount());执行上面的测试例子,打印结果如下:StopWatch'':runningtime=3509166972ns-------------------------------------------ns%Taskname--------------------------------------------1003330360029%起床2001421734057%洗漱504414878014%锁门3509锁门org.springframework.util.StopWatch$TaskInfo@12f40c253这时候的魅力你看到了吗秒表?通过多组启停方法区分业务代码块,可以得到不同代码块的执行时间;通过start方法传入taskName,为每个代码块命名;您可以对总任务耗时和每个任务耗时进行统计分析;prettyPrint()方法可以优雅的打印出统计分析信息;getTotalTimeMillis()方法,打印出花费的总时间;得到拉斯tTaskName()方法,打印最后一个任务名称;getLastTaskInfo()方法,获取上一个任务的TaskInfo,进而获取更多相关信息;有什么有用的信息?StopWatch的实现原理最后,我们再看一下源码,了解一下StopWatch的实现机制。首先看StopWatch的start方法的实现:this.startTimeNanos=System.nanoTime();}start方法记录了任务名称和任务执行时间,是根据System.nanoTime()获取的。stop方法实现如下:publicvoidstop()throwsIllegalStateException{if(this.currentTaskName==null){thrownewIllegalStateException("Can'tstopStopWatch:it'snotrunning");}longlastTime=System.nanoTime()-this.startTimeNanos;this.totalTimeNanos+=lastTime;this.lastTaskInfo=newTaskInfo(this.currentTaskName,lastTime);if(this.keepTaskList){this.taskList.add(this.lastTaskInfo);}++this.taskCount;this.currentTaskName=null;}在stop方法中,lastTime是减去两个时间戳得到的,即一个任务的执行时间;lastTime累加得到总执行时间;同时记录任务列表和任务数量统计。其他get方法是对start和stop获取的数据进行进一步的统计、分析、格式化输出。小结当我们习惯了一些功能的时候,可能会固守一种实现方式,但是如果参考其他框架中类似功能的实现,往往会有一些新的突破。如果你使用的是Spring框架,我建议你试试StopWatchAPI,它可以让你的时间统计日志更加高端。