Stopwatch
介绍
*简单的秒表,允许一些任务的计时,显示总计
*每个命名任务的运行时间和运行时间。
*
*
隐藏{@link System#nanoTime()}的使用,提高
*应用程序代码和减少计算错误的可能性。
*
*
请注意,此对象不是为线程安全而设计的,并且不使用
*同步。
*
*
该类通常用于验证概念验证期间的性能
*在开发中工作,而不是作为生产应用的一部分。
*
*
从Spring Framework 5.2开始,跟踪并报告运行时间
*纳秒。
使用
StopWatch stopWatch = new StopWatch();
stopWatch.start("taskname");
//somemethod;
stopWatch.stop();
System.out.println(stopWatch.getLastTaskName() + "=========" + stopWatch.getTotalTimeMillis());
源码分析
构造方法
/*
1.这里的id是可以重复的,只是StopWatch实例的一个标识
2.无参构造会默认调用有参构造,id取空字符串
*/
/**
* Construct a new {@code StopWatch}.
* <p>Does not start any task.
*/
public StopWatch() {
this("");
}
/**
* Construct a new {@code StopWatch} with the given ID.
* <p>The ID is handy when we have output from multiple stop watches and need
* to distinguish between them.
* <p>Does not start any task.
* @param id identifier for this stop watch
*/
public StopWatch(String id) {
this.id = id;
}
开始,停止
/*
start
1.start()方法也会默认taskName是空字符串,调用有参方法
2.通过this.currentTaskName是否为null来判断当前有没有正在计时的任务,这里并没有创建一个int变量空置,感觉是为了节省变量,省内存
3.currentTaskName,startTimeNanos用来记录当前的任务的名称和开始时间,这里任务名称也是可以重复的
*/
/**
* Start an unnamed task.
* <p>The results are undefined if {@link #stop()} or timing methods are
* called without invoking this method first.
* @see #start(String)
* @see #stop()
*/
public void start() throws IllegalStateException {
start("");
}
/**
* Start a named task.
* <p>The results are undefined if {@link #stop()} or timing methods are
* called without invoking this method first.
* @param taskName the name of the task to start
* @see #start()
* @see #stop()
*/
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();
}
/*
stop:Stopwatch只能单个单个任务记录时间,串行的,这也是一个缺点
1.通过System记录当前任务执行时间
2.记录总的运行时间,总的任务数
3.如果keepTaskList为true,将当前任务记录到队列中,注意当记录百万级时,这里的记录队列是有可能内存泄漏的
4.将当前任务名称设置为null,初始化当前任务
*/
/**
* Stop the current task.
* <p>The results are undefined if timing methods are called without invoking
* at least one pair of {@code start()} / {@code stop()} methods.
* @see #start()
* @see #start(String)
*/
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;
}
格式化输出
/*
1.shortSummary()只输出当前任务的id和运行时间
2.prettyPrint()格式化输出队列当中的所有任务,运行时间、占比、名称
*/
/**
* Get a short description of the total running time.
*/
public String shortSummary() {
return "StopWatch '" + getId() + "': running time = " + getTotalTimeNanos() + " ns";
}
/**
* Generate a string with a table describing all tasks performed.
* <p>For custom reporting, call {@link #getTaskInfo()} and use the task info
* directly.
*/
public String prettyPrint() {
StringBuilder sb = new StringBuilder(shortSummary());
sb.append('\n');
if (!this.keepTaskList) {
sb.append("No task info kept");
}
else {
sb.append("---------------------------------------------\n");
sb.append("ns % Task name\n");
sb.append("---------------------------------------------\n");
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("\n");
}
}
return sb.toString();
}

浙公网安备 33010602011771号