一、StopWatch 简介
1.1 StopWatch 是什么?
StopWatch 是 org.springframework.util 包下的一个工具类,通过它可方便的对程序执行时间进行统计。
1.2 简单使用
public class StopWatchTest {
@Test
public void test() throws InterruptedException {
StopWatch stopWatch = new StopWatch();
stopWatch.start("task_01");
Thread.sleep(3);
stopWatch.stop();
stopWatch.start("task_02");
Thread.sleep(2);
stopWatch.stop();
stopWatch.start("task_03");
Thread.sleep(4);
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());
}
}
控制台输出:
StopWatch '': running time = 10659200 ns
---------------------------------------------
ns % Task name
---------------------------------------------
003353500 031% task_01
002327200 022% task_02
004978500 047% task_03
二、StopWatch 源码解析
2.1 初始化 StopWatch
提供了两种构造函数用于初始化 StopWatch
// 用于区分秒表的主键
private final String id;
// 默认主键为空
public StopWatch() {
this("");
}
// 指定秒表主键
public StopWatch(String id) {
this.id = id;
}
2.2 启动 StopWatch
提供两种启动方式,当需要统计多个任务时,需要指定任务名称
// 当前任务名
private String currentTaskName;
// 统计开始时间
private long startTimeNanos;
public void start() throws IllegalStateException {
start("");
}
public void start(String taskName) throws IllegalStateException {
// 如果当前正在统计中将抛出异常
if (this.currentTaskName != null) {
throw new IllegalStateException("Can't start StopWatch: it's already running");
}
// 设置当前统计任务名称
this.currentTaskName = taskName;
// 记录当前时间
this.startTimeNanos = System.nanoTime();
}
2.3 停止 StopWatch
// 执行的任务个数
private int taskCount;
// 总执行时间
private long totalTimeNanos;
// 是否保留任务信息
private boolean keepTaskList = true;
// 最近一次执行的任务信息
private TaskInfo lastTaskInfo;
// 执行的任务清单列表
private final List<TaskInfo> taskList = new LinkedList<>();
public void stop() throws IllegalStateException {
if (this.currentTaskName == null) {
throw new IllegalStateException("Can't stop StopWatch: it's not running");
}
long lastTime = System.nanoTime() - this.startTimeNanos;
this.totalTimeNanos += lastTime;
this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
if (this.keepTaskList) {
this.taskList.add(this.lastTaskInfo);
}
++this.taskCount;
this.currentTaskName = null;
}
2.4 TaskInfo 对象结构
public static final class TaskInfo {
// 任务名称
private final String taskName;
// 总耗时
private final long timeNanos;
......
}
2.5 格式化输出
public String prettyPrint() {
StringBuilder sb = new StringBuilder(shortSummary());
sb.append('
');
if (!this.keepTaskList) {
sb.append("No task info kept");
}
else {
sb.append("---------------------------------------------
");
sb.append("ns % Task name
");
sb.append("---------------------------------------------
");
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMinimumIntegerDigits(9);
nf.setGroupingUsed(false);
NumberFormat pf = NumberFormat.getPercentInstance();
pf.setMinimumIntegerDigits(3);
pf.setGroupingUsed(false);
for (TaskInfo task : getTaskInfo()) {
sb.append(nf.format(task.getTimeNanos())).append(" ");
sb.append(pf.format((double) task.getTimeNanos() / getTotalTimeNanos())).append(" ");
sb.append(task.getTaskName()).append("
");
}
}
return sb.toString();
}