利用StopWatch监控Java代码运行时间和分析性能
一、背景
有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,一般我们检测某段代码执行的时间,都是以如下方式来进行的:
public static void main(String[] args) {
Long startTime = System.currentTimeMillis();
// 你的业务代码
Long endTime = System.currentTimeMillis();
Long elapsedTime = (endTime - startTime) / 1000;
System.out.println("该段总共耗时:" + elapsedTime + "s");
}
事实上该方法通过获取执行完成时间与执行开始时间的差值得到程序的执行时间,简单直接有效,但想必写多了也是比较烦人的,尤其是碰到不可描述的代码时,会更加的让人忍不住多写几个bug聊表敬意,而且如果想对执行的时间做进一步控制,则需要在程序中很多地方修改。
此时会想是否有一个工具类,提供了这些方法,刚好可以满足这种场景?
我们可以利用已有的工具类中的秒表,常见的秒表工具类
有org.springframework.util.StopWatch、org.apache.commons.lang.time.StopWatch以及谷歌提供的guava中的秒表(这个我没怎么用过)
这里重点讲下基于spring、Apache的使用
二、spring 用法
2.1 初遇
StopWatch 是位于 org.springframework.util 包下的一个工具类,通过它可方便的对程序部分代码进行计时(ms级别),适用于同步单线程代码块。简单总结一句,Spring提供的计时器StopWatch对于秒、毫秒为单位方便计时的程序,尤其是单线程、顺序执行程序的时间特性的统计输出支持比较好。
也就是说假如我们手里面有几个在顺序上前后执行的几个任务,而且我们比较关心几个任务分别执行的时间占用状况,希望能够形成一个不太复杂的日志输出,StopWatch提供了这样的功能。而且Spring的StopWatch基本上也就是仅仅为了这样的功能而实现。
想要使用它,首先你需要在你的 Maven 中引入 Spring 核心包,当然 Spring MVC 和 Spring Boot 都已经自动引入了该包:
org.springframework
spring-core
${spring.version}
对一切事物的认知,都是从使用开始,那就先来看看它的用法,会如下所示:
public static void main(String[] args) throws InterruptedException {
StopWatch stopWatch = new StopWatch();
// 任务一模拟休眠3秒钟
stopWatch.start("TaskOneName");
Thread.sleep(1000 * 3);
System.out.println("当前任务名称:" + stopWatch.currentTaskName());
stopWatch.stop();
// 任务一模拟休眠10秒钟
stopWatch.start("TaskTwoName");
Thread.sleep(1000 * 10);
System.out.println("当前任务名称:" + stopWatch.currentTaskName());
stopWatch.stop();
// 任务一模拟休眠10秒钟
stopWatch.start("TaskThreeName");
Thread.sleep(1000 * 10);
System.out.println("当前任务名称:" + stopWatch.currentTaskName());
stopWatch.stop();
// 打印出耗时
System.out.println(stopWatch.prettyPrint());
System.out.println(stopWatch.shortSummary());
// stop后它的值为null
System.out.println(stopWatch.currentTaskName());
// 最后一个任务的相关信息
System.out.println(stopWatch.getLastTaskName());
System.out.println(stopWatch.getLastTaskInfo());
// 任务总的耗时 如果你想获取到每个任务详情(包括它的任务名、耗时等等)可使用
System.out.println("所有任务总耗时:" + sw.getTotalTimeMillis());
System.out.println("任务总数:" + sw.getTaskCount());
System.out.println("所有任务详情:" + sw.getTaskInfo());
}
如图所示,StopWatch 不仅正确记录了上个任务的执行时间,并且在最后还可以给出精确的任务执行时间(纳秒级别)和耗时占比,这或许就会比我们自己输出要优雅那么一些。
2.2 源码
老规矩,由浅入深。看完用法,我们来看看源码。先看下组成 StopWatch 的属性
public class StopWatch {
/**
* 本实例的唯一 Id,用于在日志或控制台输出时区分的。
*/
private final String id;
/**
* 是否保持一个 taskList 链表
* 每次停止计时时,会将当前任务放入这个链表,用以记录任务链路和计时分析
*/
private boolean keepTaskList = true;
/**
* 任务链表
* 用来存储每个task的信息, taskInfo由taskName 和 totoalTime组成
*/
private final List
taskList; /**
* 当前任务的开始时间
*/
private long startTimeMillis;
/**
*
*/
private boolean running;
/**
* 当前任务名称
*/
private String currentTaskName;
/**
* 最后一个任务的信息
*/
private StopWatch.TaskInfo lastTaskInfo;
/**
* 任务总数
*/
private int taskCount;
/**
* 程序执行时间
*/
private long totalTimeMillis;
...
}
接下来,我们看一下StopWatch类的构造器和一些关键方法
2.3 注意事项
- StopWatch对象不是设计为线程安全的,并且不使用同步。
- 一个StopWatch实例一次只能开启一个task,不能同时start多个task
- 在该task还没stop之前不能start一个新的task,必须在该task stop之后才能开启新的task
- 若要一次开启多个,需要new不同的StopWatch实例
三、apache 用法
StopWath是 apache commons lang3 包下的一个任务执行时间监视器,与我们平时常用的秒表的行为比较类似,我们先看一下其中的一些重要方法:
org.apache.commons
commons-lang3
3.6
Apache提供的这个任务执行监视器功能丰富强大,灵活性强,如下经典实用案例:
public static void main(String[] args) throws InterruptedException {
//创建后立即start,常用
StopWatch watch = StopWatch.createStarted();
// StopWatch watch = new StopWatch();
// watch.start();
Thread.sleep(1000);
System.out.println(watch.getTime());
System.out.println("统计从开始到现在运行时间:" + watch.getTime() + "ms");
Thread.sleep(1000);
watch.split();
System.out.println("从start到此刻为止的时间:" + watch.getTime());
System.out.println("从开始到第一个切入点运行时间:" + watch.getSplitTime());
Thread.sleep(1000);
watch.split();
System.out.println("从开始到第二个切入点运行时间:" + watch.getSplitTime());
// 复位后, 重新计时
watch.reset();
watch.start();
Thread.sleep(1000);
System.out.println("重新开始后到当前运行时间是:" + watch.getTime());
// 暂停 与 恢复
watch.suspend();
System.out.println("暂停2秒钟");
Thread.sleep(2000);
// 上面suspend,这里要想重新统计,需要恢复一下
watch.resume();
System.out.println("恢复后执行的时间是:" + watch.getTime());
Thread.sleep(1000);
watch.stop();
System.out.println("花费的时间》》" + watch.getTime() + "ms");
// 直接转成s
System.out.println("花费的时间》》" + watch.getTime(TimeUnit.SECONDS) + "s");
}
四、最后
很多时候,写代码也是一种艺术,而借助这种实用工具我就觉得艺术感更强些。希望我们能有追求更加美好事物的心,这点对于接纳新知识特别重要。
此处推荐这个监视器来代替之前的的使用,能让小伙伴们更加灵活的分析你的代码。
-
JAVA +关注
关注
19文章
2317浏览量
100578 -
代码 +关注
关注
25文章
2984浏览量
64043 -
spring +关注
关注
0文章
194浏览量
13606 -
Apache +关注
关注
0文章
51浏览量
11923
发布评论请先 登录
相关推荐
STM32F429快速运行时间的最佳配置是什么?
如何最大限度地延长无线传感器的运行时间

Go运行时:4年之后
如何检查Linux服务器的运行时间

获取单片机运行时间

利用正确的静态分析实现应用

延长小型电池供电电子设备运行时间的方法

rt_thread_mdelay影响调试的运行时间怎么办
LabVIEW哪些软件需要运行时许可
利用stm32来探究一下程序运行时的栈空间是怎么分布的
测量嵌入式软件运行时间的方法
C语言运行时需要和栈的意义
利用定时器实现51单片机返回上电运行时间功能

浅析STM32代码运行时间的技巧

如何高效测量ECU的运行时间
每天累加并且保存设备运行时间以及故障时间等
如何在MCU上测量代码执行时间?
简析获取单片机代码运行时间的方法资料下载

简析如何获取单片机代码运行时间的方法

STM32设备运行时变量监视和可视化工具

伺服电机运行时发出噪声的原因分析
Maxim发布最新基础模拟收发器,旨在提高工业系统的正常运行时间
请问6747如何测量代码运行时间?
freertos的任务运行时间怎么设置
KEIL的代码运行时间功能

代码在执行过程中有一些问题会影响运行时性能
ProConOS是一款高性能PLC运行时间引擎

在运行时添加100个项目
ucosIII中的时间戳单位怎么确定一个任务的运行时间?
如何在protues中用软件仿真判断语句运行时间?
Java程序是如何运行的
Maxim发布隔离式碳化硅栅极驱动器,提供业界最佳电源效率、有效延长系统运行时间
如何在运行时更新RAM?
Labview求助,程序运行时间与设置的延迟不符
请问有C运行时库源代码吗?
电池供电设备运行时间的延长方法
电机运行时间进行排列 是分为两个部分来完成这个程序的设计的

VEE运行时错误
Android N混合使用AOT编译,解释和JIT三种运行时
运行时错误Vivado 2016.2
如何最大化汽车电池包的运行时间?
基于STM32单片机通过使用宏assert_param来实现运行时间检测

怎么在Debian上加速Chromium加载和运行时间(9)在BBB上拉伸?
PNA N5232A正常运行时间是多少
LABVIEW 如何记录机器开机时间,停机时间,和总运行时间
vrf运行时.NET事件?
请问C6678 各核运行相同的代码,但是运行时间有差异,能控制吗?
请问RX23T如何获取系统时钟,以便获取类似时间戳,如何获取此段代码运行时间?
汽车电池包的运行时间
如何用SysTick实现测量程序运行时间

基于本地任务与远程任务运行时间的CPS和PAA的概念

设定时间,已运行时间,剩余时间
紫金桥组态软件新的功能_运行时组态

Android运行中DVM和ART表现对比

评论