文章目录

  • 一、背景
  • 二、spring 用法
    • 2.1 初遇
    • 2.2 源码
    • 2.3 注意事项
  • 三、apache 用法
  • 四、最后

利用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.StopWatchorg.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 都已经自动引入了该包:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version>
</dependency>

  对一切事物的认知,都是从使用开始,那就先来看看它的用法,会如下所示:

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后它的值为nullSystem.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<StopWatch.TaskInfo> taskList;/*** 当前任务的开始时间*/private long startTimeMillis;/*** */private boolean running;/*** 当前任务名称*/private String currentTaskName;/*** 最后一个任务的信息*/private StopWatch.TaskInfo lastTaskInfo;/*** 任务总数*/private int taskCount;/*** 程序执行时间*/private long totalTimeMillis;...
}

接下来,我们看一下StopWatch类的构造器和一些关键方法

方法 说明
new StopWatch() 构建一个新的秒表,不开始任何任务。
new StopWatch(String id) 创建一个指定了id的StopWatch
String getId() 返回此秒表的ID
void start(String taskName) 不传入参数,开始一个无名称的任务的计时。
传入String类型的参数来开始指定任务名的任务计时
void stop() 停止当前任务的计时
boolean isRunning() 是否正在计时某任务
String currentTaskName() 当前正在运行的任务的名称(如果有)
long getTotalTimeMillis() 所有任务的总体执行时间(毫秒单位)
double getTotalTimeSeconds() 所有任务的总时间(以秒为单位)
String getLastTaskName() 上一个任务的名称
long getLastTaskTimeMillis() 上一个任务的耗时(毫秒单位)
int getTaskCount() 定时任务的数量
String shortSummary() 总运行时间的简短描述
String prettyPrint() 优美地打印所有任务的详细耗时情况

2.3 注意事项

  • StopWatch对象不是设计为线程安全的,并且不使用同步。
  • 一个StopWatch实例一次只能开启一个task,不能同时start多个task
  • 在该task还没stop之前不能start一个新的task,必须在该task stop之后才能开启新的task
  • 若要一次开启多个,需要new不同的StopWatch实例

三、apache 用法

  StopWath是 apache commons lang3 包下的一个任务执行时间监视器,与我们平时常用的秒表的行为比较类似,我们先看一下其中的一些重要方法:

方法 说明
new StopWatch() 构建一个新的秒表,不开始任何任务。
static StopWatch createStarted()
void start() 开始计时
void stop() 停止当前任务的计时
void reset() 重置计时
void split() 设置split点
void unsplit()
void suspend() 暂停计时, 直到调用resume()后才恢复计时
void resume() 恢复计时
long getTime() 统计从start到现在的计时
long getTime(final TimeUnit timeUnit)
long getNanoTime()
long getSplitTime() 获取从start 到 最后一次split的时间
long getSplitNanoTime()
long getStartTime()
boolean isStarted()
boolean isSuspended()
boolean isStopped()
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.6</version>
</dependency>

  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");// 直接转成sSystem.out.println("花费的时间》》" + watch.getTime(TimeUnit.SECONDS) + "s");
}

四、最后

  很多时候,写代码也是一种艺术,而借助这种实用工具我就觉得艺术感更强些。希望我们能有追求更加美好事物的心,这点对于接纳新知识特别重要。此处推荐这个监视器来代替之前的的使用,能让小伙伴们更加灵活的分析你的代码~

Java计时新姿势StopWatch相关推荐

  1. 2022年Java计时新姿势StopWatch

    一.背景   有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,一般我们检测某段代码执行的时间,都是以如下方式来进行的: pub ...

  2. java stopwatch_Java计时新姿势StopWatch详解

    一.最简单的计时 在我们的程序中不免需要对某一个运算或者方法进行计时,以便我们来观察该运算或方法是否符合我们的预期,所以在我们刚开始接触 Java 的时候都能写出类似下面这样的代码来计时: publi ...

  3. JDK9新特性实战:简化流关闭新姿势

    转载自 JDK9新特性实战:简化流关闭新姿势. 做Java开发的都知道,每个资源的打开都需要对应的关闭操作,不然就会使资源一直占用而造成资源浪费,从而降低系统性能. 关于资源的关闭操作,从JDK7-J ...

  4. #开工新姿势#开启一年新征程,云社区叫你来充电啦!

    摘要:这有份开工红包等你来拿哟~~ 一年之计在于春 值此春暖花开.开学复工之季 华为云社区"内容共创计划"再次来袭! 无论你是正在读书的学生开发者,还是经验丰富的职场技术人,都非常 ...

  5. 避免过多if - else的新姿势:策略模式、工厂 + 策略

    目录 前言 需求 编码实现 思考 策略模式 什么是策略模式? 编码 深思 工厂 + 策略 toMap 效果 后续 前言 避免过多if - else的新姿势:卫语句.小函数.多态.反射 在之前文章说到, ...

  6. 三种新姿势:帮你干掉过多的if-else

    点击上方"Java基基",选择"设为星标" 做积极的人,而不是积极废人! 每天 14:00 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java ...

  7. [解锁新姿势] 回想起被 `if-else` 支配的恐惧,我们要打倒 if - else

    前言 [解锁新姿势] 兄dei,你代码需要优化了 在之前文章说到,简单 if-else,可以使用 卫语句 进行优化.但是在实际开发中,往往不是简单 if-else 结构,我们通常会不经意间写下如下代码 ...

  8. IntelliJ IDEA 使用 Java 11新特性以及Java 8 以来的Java 11新特性介绍

    文章目录 Java 11 安装 IDEA 设置 特性1:lambda表达式中允许使用var 特性2: String新增REPEAT 方法,方便拷贝字符串 特性3: 文件读写更方便:readString ...

  9. Jakarta EE:云原生Java的新平台

    \ 看新闻很累?看技术新闻更累?试试下载InfoQ手机客户端,每天上下班路上听新闻,有趣还有料! \ \\ 在今年的JAX大会上,Eclipse基金会的执行董事Mike Milinkovich专门介绍 ...

最新文章

  1. 数字孪生城市应用【案例集】,附下载
  2. Intel Realsense D435 摄像头插入电脑无法监测(识别)的可能原因及解决方案 USB SCP overflow
  3. scratch跳一跳游戏脚本_超级丛林跳游戏下载-超级丛林跳最新版下载v1.01.5026 安卓版...
  4. 丑数 Humble Numbers
  5. 对一个“世纪数学难题”的重新思考
  6. jq往字符串中插入_jq: dom-插入
  7. 如何自学python-作为一个Python自学者,怎样学好Python?
  8. CSS 自定义属性 -- 使用 JS 和不使用 JS
  9. tushare获取沪深300指数历史_tushare正确爬取 指数数据
  10. 旅夜书怀,月夜忆舍弟,天末怀李白,春望,旅宿,与诸子登岘山,宴梅道士山房,章台夜思,淮上喜会梁州故人,赋得暮雨送李曹
  11. 2022年执业兽医考试经典试题及答案
  12. 每个家庭将有一台计算机英语,2011年6月英语四级考试模拟试题及答案9
  13. PD3.1 140W双C快充解决方案
  14. 数据分析(python系)
  15. 服务号模板消息群发二代服务器,服务号模板消息群发
  16. Python traceback模块:获取异常信息
  17. ps 读取计算机特定首选项时出错,Photoshop“正在读取首选项”无法响应的解决办法...
  18. Selenium IDE的介绍
  19. HbuilderX插件下载失败的解决方法
  20. 有效市场假说和盲点套利

热门文章

  1. usnews 计算机 2017,2017年USNEWS美国研究生计算机工程专业排名
  2. 【网页打不开的解决方法总汇】
  3. 网页title顶部标题图片
  4. 转发和重定向的区别,web路径问题
  5. 给MX4刷入Ubuntu Touch
  6. 女生美容养颜喝什么茶好
  7. Docker基本命令使用——(1)
  8. sqlserver中case when then用法
  9. 《Docker系列》Error response from daemon: driver failed... Error: failed to start containers...
  10. 蓝牙音频双剑客(二)--高质量音频分布协议(A2DP) SBC编解码算法