2022年Java计时新姿势StopWatch
一、背景
有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,一般我们检测某段代码执行的时间,都是以如下方式来进行的:
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.StopWatch、org.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");
}
复制代码
复制代码
四、最后
很多时候,写代码也是一种艺术,而借助这种实用工具我就觉得艺术感更强些。希望我们能有追求更加美好事物的心,这点对于接纳新知识特别重要。此处推荐这个监视器来代替之前的的使用,能让小伙伴们更加灵活的分析你的代码~
2022年Java计时新姿势StopWatch相关推荐
- Java计时新姿势StopWatch
文章目录 一.背景 二.spring 用法 2.1 初遇 2.2 源码 2.3 注意事项 三.apache 用法 四.最后 利用StopWatch监控Java代码运行时间和分析性能 一.背景 有时 ...
- java stopwatch_Java计时新姿势StopWatch详解
一.最简单的计时 在我们的程序中不免需要对某一个运算或者方法进行计时,以便我们来观察该运算或方法是否符合我们的预期,所以在我们刚开始接触 Java 的时候都能写出类似下面这样的代码来计时: publi ...
- 2022年最细Java 17新特性,是真的猛,被征服了!
SpringBoot 正式支持Java 17,Kafka3.0弃用Java8 Spring Boot 2.5.5是Spring Boot 第一个支持Java 17的版本.现在你已经可以从Spring ...
- Java前沿分享:value或许成为java的新关键字
2022年Java将有什么新的特性和改进,我相信很多Java开发者都想知道.结合Java语言架构师布莱恩·格茨(Brian Goetz)最近的一些分享,胖哥给大家爆个料.老规矩,点赞.再看.转发.星标 ...
- JDK9新特性实战:简化流关闭新姿势
转载自 JDK9新特性实战:简化流关闭新姿势. 做Java开发的都知道,每个资源的打开都需要对应的关闭操作,不然就会使资源一直占用而造成资源浪费,从而降低系统性能. 关于资源的关闭操作,从JDK7-J ...
- #开工新姿势#开启一年新征程,云社区叫你来充电啦!
摘要:这有份开工红包等你来拿哟~~ 一年之计在于春 值此春暖花开.开学复工之季 华为云社区"内容共创计划"再次来袭! 无论你是正在读书的学生开发者,还是经验丰富的职场技术人,都非常 ...
- 避免过多if - else的新姿势:策略模式、工厂 + 策略
目录 前言 需求 编码实现 思考 策略模式 什么是策略模式? 编码 深思 工厂 + 策略 toMap 效果 后续 前言 避免过多if - else的新姿势:卫语句.小函数.多态.反射 在之前文章说到, ...
- 《2022年Java开发者生产力报告》出炉啦
2022 年,Perforce 公司没有「爽约」,< 2022年 Java 开发人员生产力报告 >如期而至. 该报告基于对全球 Java 开发专业人士的调查,持续时间为 2021 年 10 ...
- Java 8 新特性 宋红康跟学
Java 8 新特性 Java 8 新特性简介 思维导图 并行流与串行流 Lambda表达式 Lambda 表达式语法 语法格式一:无参,无返回值,Lambda体只需一条语句 语法格式二:Lambda ...
最新文章
- FD.io/VPP — VPP Agent — Quickstart
- Dubbo 源码分析 - 集群容错之Directory
- android编程 自动裁剪图片,Android编程实现调用相册、相机及拍照后直接裁剪的方法...
- 如何压测基于容器服务ACK托管的DUBBO服务
- Educational Codeforces Round 1
- testlink匹配mysql8_如何安装Testlink
- BeginnersBook Java 示例
- 线程池与Threadlocal
- 什么是基金转换?转换费用如何收取?
- 2019,一年一度的高考季来临,作文又成热门话题
- 计算机excel保留一位小数,excel表格数据取一位小数-excel保留一位小数
- Excel代替matplotlib画散点图 拟合曲线
- 关于树莓派无法解析域名的错误
- 单位内网访问外网的二种方式
- PS问题汇总2017
- android 开启子线程方法,android中开启子线程
- 对于M1卡密钥控制字设置的总结
- Python 生成个性二维码
- 什么是X.509证书?X.509证书工作原理及应用?
- Walk Through the Fire,Is there a way out