今天看spring源码工具类时发现一个好用的东西所以分享出来
该类在spring源码中
这个项目的 org.springframework.util.StopWatch 有兴趣可以自己看,我也是刚开始看源码,还有很多不足的地方
以下是该类的具体源码:
package org.springframework.util; import java.text.NumberFormat; import java.util.LinkedList; import java.util.List; import org.springframework.lang.Nullable; /** * Simple stop watch, allowing for timing of a number of tasks, * exposing total running time and running time for each named task. * * <p>Conceals use of {@code System.currentTimeMillis()}, improving the * readability of application code and reducing the likelihood of calculation errors. * * <p>Note that this object is not designed to be thread-safe and does not * use synchronization. * * <p>This class is normally used to verify performance during proof-of-concepts * and in development, rather than as part of production applications. * * 简单的秒表,允许对大量任务进行计时,显示每个命名任务的总运行时间和运行时间。 * <p>隐藏{@code System.currentTimeMillis()}的使用,提高应用程序代码的可读性并减少计算错误的可能性。 * <p>请注意,此对象不是为线程安全而设计的,并且不使用同步。 * <p>此类通常用于在概念验证和开发过程中验证性能,而不是作为生产应用程序的一部分。 * * @author Rod Johnson * @author Juergen Hoeller * @author Sam Brannen * @since May 2, 2001 */ public class StopWatch { /** * Identifier of this stop watch. * Handy when we have output from multiple stop watches * and need to distinguish between them in log or console output. * 此秒表的标识符。 * 当我们有来自多个秒表的输出,并且需要在日志或控制台输出中区分它们时,这非常方便。 */ private final String id; // 保留任务列表 private boolean keepTaskList = true; // 任务列表 private final List<TaskInfo> taskList = new LinkedList<>(); /** Start time of the current task. 当前任务的开始时间。 */ private long startTimeMillis; /** Name of the current task. 当前任务的名称。*/ @Nullable private String currentTaskName; // 上次任务信息 @Nullable private TaskInfo lastTaskInfo; //任务计数 private int taskCount; /** Total running time. 总运行时间。*/ private long totalTimeMillis; /** * Construct a new stop watch. Does not start any task. * 建造一个新的秒表。不启动任何任务。 */ public StopWatch() { this(""); } /** * Construct a new stop watch with the given id. * Does not start any task. * @param id identifier for this stop watch. * Handy when we have output from multiple stop watches * and need to distinguish between them. * * 使用给定id构造新秒表。不启动任何任务。 * @param id 此秒表的标识符。 * 当我们有来自多个秒表的输出并且需要区分它们时,它非常方便。 */ public StopWatch(String id) { this.id = id; } /** * Return the id of this stop watch, as specified on construction. * @return the id (empty String by default) * @since 4.2.2 * @see #StopWatch(String) * * 返回此秒表的id,如施工图所示。 * @return id(默认为空字符串) */ public String getId() { return this.id; } /** * Determine whether the TaskInfo array is built over time. Set this to * "false" when using a StopWatch for millions of intervals, or the task * info structure will consume excessive memory. Default is "true". * * 确定TaskInfo数组是否随时间构建。 * 在数百万次使用秒表时,将此设置为“false”,否则任务信息结构将消耗过多内存。默认值为“true”。 */ public void setKeepTaskList(boolean keepTaskList) { this.keepTaskList = keepTaskList; } /** * Start an unnamed task. The results are undefined if {@link #stop()} * or timing methods are called without invoking this method. * @see #stop() * * 启动一个未命名的任务。如果在不调用此方法的情况下调用{@link #stop())}或计时方法,则结果是未定义的。 */ public void start() throws IllegalStateException { start(""); } /** * Start a named task. The results are undefined if {@link #stop()} * or timing methods are called without invoking this method. * @param taskName the name of the task to start * @see #stop() * * 启动命名任务。如果在不调用此方法的情况下调用{@link #stop())}或计时方法,则结果是未定义的。 * @param taskName 要启动的任务的名称 */ 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.startTimeMillis = System.currentTimeMillis(); } /** * Stop the current task. The results are undefined if timing * methods are called without invoking at least one pair * {@code start()} / {@code stop()} methods. * @see #start() * * 将当前任务置于顶部。如果在不调用至少一对的情况下调用计时方法,则结果是未定义的 * {@code start()} / {@code stop()} 方法. */ public void stop() throws IllegalStateException { if (this.currentTaskName == null) { throw new IllegalStateException("Can't stop StopWatch: it's not running");//“无法停止秒表:它没有运行” } long lastTime = System.currentTimeMillis() - this.startTimeMillis; this.totalTimeMillis += lastTime; this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime); if (this.keepTaskList) { this.taskList.add(this.lastTaskInfo); } ++this.taskCount; this.currentTaskName = null; } /** * Return whether the stop watch is currently running. * @see #currentTaskName() * * 返回秒表当前是否正在运行。 */ public boolean isRunning() { return (this.currentTaskName != null); } /** * Return the name of the currently running task, if any. * @since 4.2.2 * @see #isRunning() * * 返回当前正在运行的任务的名称(如果有)。 */ @Nullable public String currentTaskName() { return this.currentTaskName; } /** * Return the time taken by the last task. * 返回上一个任务所用的时间。 */ public long getLastTaskTimeMillis() throws IllegalStateException { if (this.lastTaskInfo == null) { throw new IllegalStateException("No tasks run: can't get last task interval");//“未运行任务:无法获取上次任务间隔” } return this.lastTaskInfo.getTimeMillis(); } /** * Return the name of the last task. * 返回最后一个任务的名称。 */ public String getLastTaskName() throws IllegalStateException { if (this.lastTaskInfo == null) { throw new IllegalStateException("No tasks run: can't get last task name");//“未运行任务:无法获取上次任务名称” } return this.lastTaskInfo.getTaskName(); } /** * Return the last task as a TaskInfo object. * 将上一个任务作为TaskInfo对象返回。 */ public TaskInfo getLastTaskInfo() throws IllegalStateException { if (this.lastTaskInfo == null) { throw new IllegalStateException("No tasks run: can't get last task info");//“未运行任务:无法获取上次任务信息” } return this.lastTaskInfo; } /** * Return the total time in milliseconds for all tasks. * 返回所有任务的总时间(以毫秒为单位)。 */ public long getTotalTimeMillis() { return this.totalTimeMillis; } /** * Return the total time in seconds for all tasks. * 返回所有任务的总时间(秒)。 */ public double getTotalTimeSeconds() { return this.totalTimeMillis / 1000.0; } /** * Return the number of tasks timed. * 返回已计时的任务数。 */ public int getTaskCount() { return this.taskCount; } /** * Return an array of the data for tasks performed. * 返回所执行任务的数据数组。 */ public TaskInfo[] getTaskInfo() { if (!this.keepTaskList) { throw new UnsupportedOperationException("Task info is not being kept!");//“未保留任务信息!” } return this.taskList.toArray(new TaskInfo[0]); } /** * Return a short description of the total running time. * 返回总运行时间的简短说明。 */ public String shortSummary() { //“秒表”:运行时间(毫秒)= return "StopWatch '" + getId() + "': running time (millis) = " + getTotalTimeMillis(); } /** * Return a string with a table describing all tasks performed. * For custom reporting, call getTaskInfo() and use the task info directly. * 返回一个字符串,其中包含一个描述所执行的所有任务的表。 * 对于自定义报告,请调用getTaskInfo()并直接使用任务信息。 */ 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("ms % Task name\n");//ms%任务名称\n sb.append("-----------------------------------------\n"); NumberFormat nf = NumberFormat.getNumberInstance(); nf.setMinimumIntegerDigits(5); nf.setGroupingUsed(false); NumberFormat pf = NumberFormat.getPercentInstance(); pf.setMinimumIntegerDigits(3); pf.setGroupingUsed(false); for (TaskInfo task : getTaskInfo()) { sb.append(nf.format(task.getTimeMillis())).append(" "); sb.append(pf.format(task.getTimeSeconds() / getTotalTimeSeconds())).append(" "); sb.append(task.getTaskName()).append("\n"); } } return sb.toString(); } /** * Return an informative string describing all tasks performed * For custom reporting, call {@code getTaskInfo()} and use the task info directly. * * 返回描述为自定义报告执行的所有任务的信息字符串,调用{@code getTaskInfo()}并直接使用任务信息。 */ @Override public String toString() { StringBuilder sb = new StringBuilder(shortSummary()); if (this.keepTaskList) { for (TaskInfo task : getTaskInfo()) { sb.append("; [").append(task.getTaskName()).append("] took ").append(task.getTimeMillis()); long percent = Math.round((100.0 * task.getTimeSeconds()) / getTotalTimeSeconds()); sb.append(" = ").append(percent).append("%"); } } else { sb.append("; no task info kept");//; 没有保存任务信息 } return sb.toString(); } /** * Inner class to hold data about one task executed within the stop watch. * 内部类,用于保存有关秒表中执行的一个任务的数据。 */ public static final class TaskInfo { private final String taskName; private final long timeMillis; TaskInfo(String taskName, long timeMillis) { this.taskName = taskName; this.timeMillis = timeMillis; } /** * Return the name of this task. * 返回此任务的名称。 */ public String getTaskName() { return this.taskName; } /** * Return the time in milliseconds this task took. * 返回此任务所用的时间(以毫秒为单位)。 */ public long getTimeMillis() { return this.timeMillis; } /** * Return the time in seconds this task took. * 返回此任务所用的时间(以秒为单位)。 */ public double getTimeSeconds() { return (this.timeMillis / 1000.0); } } }
以下是我的使用示例:
import org.junit.Test; import org.springframework.util.StopWatch; /** * <T>User:cf</T> * <T>Description:秒表测试</T> * <T>Create time:2021/10/14 10:07</T> * <T>Company: dolph-tech</T> * <T>Update record(who,time,message):</T> * <T>date 2021年 10月 14日 */ public class StopWatchTest { @Test public void no1() throws InterruptedException { StopWatch stopWatch = new StopWatch("MyStopWatch"); String id = stopWatch.getId(); System.out.println("秒表id:" + id); String s = stopWatch.currentTaskName(); System.out.println("当前任务名称" + s); boolean running = stopWatch.isRunning(); System.out.println("是否正在运行:" + running); String s1 = stopWatch.prettyPrint(); System.out.println("运行时间:" + s1); //开始任务 命名为MyStopWatchTest stopWatch.start("MyStopWatchTest"); Thread.sleep(6000 * 5); String s4 = stopWatch.currentTaskName(); System.out.println("当前任务名称" + s4); //任务停止 stopWatch.stop(); //开始任务 命名为MyStopWatchTest2 stopWatch.start("MyStopWatchTest2"); Thread.sleep(6000 * 5); String s5 = stopWatch.currentTaskName(); System.out.println("当前任务名称" + s5); //任务停止 stopWatch.stop(); String s3 = stopWatch.currentTaskName(); System.out.println("当前任务名称" + s3); String s2 = stopWatch.prettyPrint(); System.out.println("运行时间:" + s2); } }
以下是示例输出:
秒表id:MyStopWatch
当前任务名称null
是否正在运行:false
运行时间:StopWatch 'MyStopWatch': running time (millis) = 0
-----------------------------------------
ms % Task name
-----------------------------------------
当前任务名称MyStopWatchTest
当前任务名称MyStopWatchTest2
当前任务名称null
运行时间:StopWatch 'MyStopWatch': running time (millis) = 60001
-----------------------------------------
ms % Task name
-----------------------------------------
30000 050% MyStopWatchTest
30001 050% MyStopWatchTest2
总结:
该工具类可以在我们应用程序测试时使用,通过任务名称的形式区分调用不同方法调用时的使用时间,以及整个应用程序的用时,非常方便的区分各个方法的用时,不在需要自己获取方法开始时间和结束时间然后计算