Java中StopWatch类的使用 您所在的位置:网站首页 start有什么用法 Java中StopWatch类的使用

Java中StopWatch类的使用

2024-04-22 22:52| 来源: 网络整理| 查看: 265

以前本人在计算某个代码块执行速度的时候,通常是使用获取前后两个时间戳,然后计算差值得到执行时间,后来知道了还有一个专门用于计算执行的时间的码表类。

为何要用StopWatch

首先说明这个StopWatch有什么便利之处,我们为什么使用它

其实最大的好处就是代码量少,现在比较最简单一个例子

import org.springframework.util.StopWatch; public class TestStopWatch { public static void main(String[] args) throws Exception{ testUseCurrentMills(); testUseCurrentStopWatch(); } static void testUseCurrentMills() throws InterruptedException { long start = System.currentTimeMillis(); Thread.sleep(3000); long end = System.currentTimeMillis(); System.out.println("执行时间"+(end - start)); } static void testUseCurrentStopWatch()throws InterruptedException { StopWatch stopWatch = new StopWatch("测试"); stopWatch.start(); Thread.sleep(3000); stopWatch.stop(); System.out.println(stopWatch.shortSummary()); } }

貌似看起来StopWatch比我们以前使用的还多一行,其实StopWatch优势在于对于多个代码块的计算,StopWatch可以提供单独的任务执行时间,以及任务的汇总时间,现在我们以计算三个代码块执行时间为例

import org.springframework.util.StopWatch; public class TestStopWatch { public static void main(String[] args) throws Exception{ testUseCurrentMills(); testUseCurrentStopWatch(); } static void testUseCurrentMills() throws InterruptedException { long start = System.currentTimeMillis(); Thread.sleep(1000); long end1 = System.currentTimeMillis(); System.out.println("代码块1执行时间"+(end1 - start)); Thread.sleep(2000); long end2 = System.currentTimeMillis(); System.out.println("代码块2执行时间"+(end2 - end1)); Thread.sleep(3000); long end3 = System.currentTimeMillis(); System.out.println("代码块3执行时间"+(end3 - end2)); System.out.println("总共执行时间"+(end3 - start)); } static void testUseCurrentStopWatch()throws InterruptedException { StopWatch stopWatch = new StopWatch("测试代码块组"); stopWatch.start("代码块1"); Thread.sleep(1000); stopWatch.stop(); stopWatch.start("代码块2"); Thread.sleep(2000); stopWatch.stop(); stopWatch.start("代码块3"); Thread.sleep(3000); stopWatch.stop(); System.out.println(stopWatch.prettyPrint()); } } 代码块1执行时间1000 代码块2执行时间2001 代码块3执行时间3000 总共执行时间6001 StopWatch '测试代码块组': running time (millis) = 6002 ----------------------------------------- ms % Task name ----------------------------------------- 01001 017% 代码块1 02000 033% 代码块2 03001 050% 代码块3

通过上面代码比对,我们发现使用StopWatch,我们可以更加将注意力关注到实际业务代码上,只需要在业务代码的开始和结束,分别调用start()和stop()方法,而不用像以前一样,不断自己的手动获取时间,手动打印,最终所有任务结束后,也可以获取所有任务的执行时间,合计时间,以及耗时占比。StopWatch还有其他一些功能,我们可以通过阅读源代码来了解一些。

StopWatch类的使用

StopWatch 共有2个构造方法,1个内部类,9个字段。

/** * 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. */ public StopWatch(String id) { this.id = id; }

这两个构造函数的区别在于,有参构造会把传入的字符串作为这个码表的名称表示,增加易读性,在打印信息时会把这个id加上。

/** * 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 taskList = new LinkedList(); /** Start time of the current task */ private long startTimeMillis; /** Is the stop watch currently running? */ private boolean running; /** Name of the current task */ private String currentTaskName; private TaskInfo lastTaskInfo; private int taskCount; /** Total running time */ private long totalTimeMillis;

id 作为多个码表区分标识

keepTaskList 开关是否保存执行过的任务列表,默认为true保存

taskList 存储执行的计时任务列表

startTimeMillis当前任务的开始时间

running 判断当前是否在计时

currentTaskName 当前任务的名称

lastTaskInfo 最后一次执行的计时任务

taskCount 累计执行的计时任务数量

totalTimeMillis 所有任务累计耗时

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); } }

计时任务包含2个属性,一个是名称,一个是耗时,方法也很简单,大家一看就明白

接下来看StopWatch 的具体方法(对于getter和setter方法就不做讲解)

/** * Start an unnamed task. The results are undefined if {@link #stop()} * or timing methods are called without invoking this method. * @see #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() */ public void start(String taskName) throws IllegalStateException { if (this.running) { throw new IllegalStateException("Can't start StopWatch: it's already running"); } this.running = true; this.currentTaskName = taskName; this.startTimeMillis = System.currentTimeMillis(); }

start有2个重载方法,调用无参的那个,实际会自动赋值一个空串调用有参start方法

有参方法进来会首先判断当前是否已在计时,如果是,则抛出异常。

接下来回下盖计时状态为开始计时,将传递进来的参数作为最近计时任务的名称存储

以及获取当前时间戳作为当前计时任务的开始时间

/** * 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() */ public void stop() throws IllegalStateException { if (!this.running) { 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(lastTaskInfo); } ++this.taskCount; this.running = false; this.currentTaskName = null; }

stop方法进来会判断是否在计时,如果没有,也会抛出状态异常

然后通过获取当前时间戳减去我们start方法存储的开始时间戳得到本次任务耗时

同时将本次耗时累加到码表的任务合计耗时

如果保存计时任务属性为true,将本次任务加入到任务列表

累加任务数量,将计时状态设置为否,清空当前任务名称

这里源码作者说了,start和stop方法一定是成对出现的,否则一定会抛出异常

/** * 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. */ 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"); 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(); } @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(); }

StopWatch 提供了3个输出方法

第一个shortSummary 只会输出当前码表id和累计耗时,第二个prettyPrint在第一个的基础上拼接了每一个task的耗时毫秒,耗时占比,任务名称,这个比较常用,最后一个是toString方法,与第二个相比,少了数据格式化,其他的没有差异。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有