相关阅读

【小家java】java5新特性(简述十大新特性) 重要一跃
【小家java】java6新特性(简述十大新特性) 鸡肋升级
【小家java】java7新特性(简述八大新特性) 不温不火
【小家java】java8新特性(简述十大新特性) 饱受赞誉
【小家java】java9新特性(简述十大新特性) 褒贬不一
【小家java】java10新特性(简述十大新特性) 小步迭代
【小家java】java11新特性(简述八大新特性) 首个重磅LTS版本


前言

编码过程中我们经常会希望得到一段代码(一个方法)的执行时间,本文将介绍两种时间监视器(秒表)来让你优雅的、灵活的处理这个问题。

Java源生方式

这种方式最最简单,最好理解,当然也是最为常用:我们自己书写。
例如:我们如果要统计一段代码的执行时间,经常会这么来写:

    public static void main(String[] args) {long startTime = System.currentTimeMillis();   //获取开始时间//函数主体代码//...long endTime = System.currentTimeMillis(); //获取结束时间System.out.println("程序运行时间: " + (endTime - startTime) + "ms");}

大多数时候我们使用ms来表示即可,但是这么写缺乏灵活性。倘若我们要展示成纳秒、秒、甚至分钟,还得我们自己处理(把毫秒值拿来进行转换~ )

当然可能到了JDK8以后,我们这么做能变得稍微灵活一些:可以这么处理:

    public static void main(String[] args) {Instant start = Instant.now();//doSomething();Instant end = Instant.now();Duration duration = Duration.between(start, end);System.out.println("millis = " + duration.toMillis());}

这个比上面灵活度强一些。但也还是有一定的缺点:步骤稍显复杂,总体上还是不够优雅,也不是那么的灵活。
那么本文针对此问题介绍一个工具:StopWatch执行时间监视器。借助它来统计我们程序的执行时间,带给非常多的方便和优雅。

StopWatch需要依赖额外的Jar:commons-lang3或者spring-core,但因这两个Jar是Java开发中都必导的,因此依赖兼容性方面可以忽略

StopWatch有很多开源的框架都有提供类似的功能:比如Apache的commons-lang3,当然还有Spring framwork自己提供的,本文将针对此俩分别做介绍~

Commons-lang3的StopWatch

Apache提供的这个任务执行监视器功能丰富强大(比Spring的强大),灵活性强,如下经典实用案例:

    public static void main(String[] args) throws Exception {StopWatch watch = StopWatch.createStarted(); //创建后立即start,常用//StopWatch watch = new StopWatch();//watch.start();Thread.sleep(1000);System.out.println("统计从开始到现在运行时间:" + watch.getTime() + "ms"); //1000msThread.sleep(1000);watch.split();System.out.println("从start到此刻为止的时间:" + watch.getTime());System.out.println("从开始到第一个切入点运行时间:" + watch.getSplitTime()); //2245Thread.sleep(1000);watch.split();System.out.println("从开始到第二个切入点运行时间:" + watch.getSplitTime());watch.reset(); //重置后必须使用start方法watch.start();Thread.sleep(1000);System.out.println("重新开始后到当前运行时间是:" + watch.getTime()); //1000watch.suspend(); //暂停Thread.sleep(6000); //模拟暂停6秒钟watch.resume(); //上面suspend,这里要想重新统计,需要恢复一下System.out.println("恢复后执行的时间是:" + watch.getTime()); //1000  注意此时这个值还是1000watch.stop();System.out.println("花费的时间》》" + watch.getTime() + "ms"); //1002msSystem.out.println("花费的时间》》" + watch.getTime(TimeUnit.SECONDS) + "s"); //1s 可以直接转成s}

打印结果:

统计从开始到现在运行时间:1007ms
从start到此刻为止的时间:2008
从开始到第一个切入点运行时间:2008
从开始到第二个切入点运行时间:3009
重新开始后到当前运行时间是:1000
恢复后执行的时间是:1000
花费的时间》》1001ms
花费的时间》》1s

如上就是StopWatch的基本使用方法,足以见到了它的强大吧,当然使用起来复杂度也是提升了些的。

核心原理解释

原理相对简单,简单看看源码便知:

// @since 2.0
public class StopWatch {// @since 3.5  这个静态方法出现得稍微晚点哦~public static StopWatch createStarted() {final StopWatch sw = new StopWatch();sw.start();return sw;}// 这些成员变量是实现的核心~~~~~~~~~~~~~~private State runningState = State.UNSTARTED;private SplitState splitState = SplitState.UNSPLIT;private long startTime;// 思考:为何有了nonaTime这里还得记录一个Millis Time呢???// 因为nanoTime只能拿来计算差值(耗时) 但是getStartTime()这个老API还得靠MillsTime~~~private long startTimeMillis;private long stopTime;// 可见:start方法可不是能够多次调用的哦~~和状态是有关的public void start() {if (this.runningState == State.STOPPED) {throw new IllegalStateException("Stopwatch must be reset before being restarted. ");}if (this.runningState != State.UNSTARTED) {throw new IllegalStateException("Stopwatch already started. ");}this.startTime = System.nanoTime();this.startTimeMillis = System.currentTimeMillis();this.runningState = State.RUNNING;}// 停表时,最重要的是记录下了stopTime 的值~~~然后标记状态public void stop() {if (this.runningState != State.RUNNING && this.runningState != State.SUSPENDED) {throw new IllegalStateException("Stopwatch is not running. ");}if (this.runningState == State.RUNNING) {this.stopTime = System.nanoTime();}this.runningState = State.STOPPED;}// 状态变为非开始状态...public void reset() {this.runningState = State.UNSTARTED;this.splitState = SplitState.UNSPLIT;}// 暂停:stopTime 也给了一个值public void suspend() {if (this.runningState != State.RUNNING) {throw new IllegalStateException("Stopwatch must be running to suspend. ");}this.stopTime = System.nanoTime();this.runningState = State.SUSPENDED;}// 这两个方法是获取差值的public long getTime() {return getNanoTime() / NANO_2_MILLIS;}// @since 3.5public long getTime(final TimeUnit timeUnit) {return timeUnit.convert(getNanoTime(), TimeUnit.NANOSECONDS);}// @since 2.4 老API  这叫获取启动的时间(啥时候启动的)public long getStartTime() {if (this.runningState == State.UNSTARTED) {throw new IllegalStateException("Stopwatch has not been started");}// System.nanoTime is for elapsed timereturn this.startTimeMillis;}
}

可以看到原理是很简单的,无非就是包装了暂停、回复、split等功能嘛

使用细节

==getTimegetSplitTime有啥区别呢?==
为了说明问题,此处我们看看getNanoTime()getSplitNanoTime()亦可:

    public long getNanoTime() {if (this.runningState == State.STOPPED || this.runningState == State.SUSPENDED) {return this.stopTime - this.startTime;} else if (this.runningState == State.UNSTARTED) {return 0;} else if (this.runningState == State.RUNNING) {return System.nanoTime() - this.startTime;}throw new RuntimeException("Illegal running state has occurred.");}public long getSplitNanoTime() {if (this.splitState != SplitState.SPLIT) {throw new IllegalStateException("Stopwatch must be split to get the split time. ");}return this.stopTime - this.startTime;}

我们发现:

  • 调用getSplit...相关方法前,必须先调用Split方法

spilit()方法源码如下:

    public void split() {if (this.runningState != State.RUNNING) {throw new IllegalStateException("Stopwatch is not running. ");}this.stopTime = System.nanoTime();this.splitState = SplitState.SPLIT;}

在调用split方法后,watch的状态改为了SPLIT且,且,且stopTime 设置为了当前时间。因此此处我们的stopTime停止了,这个时候调用getSplitNanoTime(),返回的是start到split那时的时间差值。因此用此方法可以插入先停止stopTime()(有点插队的赶脚),最后再输出(先插好队,最后在输出)~

getTime()就是拿当前的时间戳,减去startTime,一般不涉及到stopTime的值,因此splitTime处理计算时间显然更加的灵活,但是,一般我们使用getTime()就足够了

Spring的StopWatch

Spring提供的这个任务监视器,我还是蛮喜欢使用的,因为一个它能够帮我同事监控多个任务,使用起来也很方便。先看一个简单的使用案例:

注意:一个监视器能够记录多个任务的执行时间这个特点非常重要哦~
比如:我们可以记录多段代码耗时时间,然后一次性打印~

    public static void main(String[] args) throws Exception {// 强烈每一个秒表都给一个id,这样查看日志起来能够更加的精确// 至于Id 我觉得给UUID是可行的~StopWatch sw = new StopWatch(UUID.randomUUID().toString());sw.start("起床");Thread.sleep(1000);System.out.println("当前任务名称:" + sw.currentTaskName());sw.stop();sw.start("洗漱");Thread.sleep(2000);System.out.println("当前任务名称:" + sw.currentTaskName());sw.stop();sw.start("锁门");Thread.sleep(500);System.out.println("当前任务名称:" + sw.currentTaskName());sw.stop();System.out.println(sw.prettyPrint()); // 这个方法打印在我们记录日志时是非常友好的  还有百分比的分析哦System.out.println(sw.shortSummary());System.out.println(sw.currentTaskName()); // stop后它的值为null// 最后一个任务的相关信息System.out.println(sw.getLastTaskName());System.out.println(sw.getLastTaskInfo());// 任务总的耗时  如果你想获取到每个任务详情(包括它的任务名、耗时等等)可使用System.out.println("所有任务总耗时:" + sw.getTotalTimeMillis());System.out.println("任务总数:" + sw.getTaskCount());System.out.println("所有任务详情:" + sw.getTaskInfo()); // 拿到所有的任务}

打印:

当前任务名称:起床
当前任务名称:洗漱
当前任务名称:锁门
StopWatch 'd6ba9412-d551-4ba7-8b0e-1b7ccb42855d': running time (millis) = 3504
-----------------------------------------
ms     %     Task name
-----------------------------------------
01001  029%  起床
02000  057%  洗漱
00503  014%  锁门StopWatch 'd6ba9412-d551-4ba7-8b0e-1b7ccb42855d': running time (millis) = 3504
null
锁门
org.springframework.util.StopWatch$TaskInfo@2d554825
所有任务总耗时:3504
任务总数:3
所有任务详情:[Lorg.springframework.util.StopWatch$TaskInfo;@68837a77

我个人偏爱使用Spring提供的这个监视器,是因为它提供的prettyPrint()打印在日志里进行分析可以非常的直观,并且我觉得提供的多任务支持也更加实用一点,当然仅仅个人偏好而已~

最后

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

知识交流

若文章格式混乱,可点击:原文链接-原文链接-原文链接-原文链接-原文链接

==The last:如果觉得本文对你有帮助,不妨点个赞呗。当然分享到你的朋友圈让更多小伙伴看到也是被作者本人许可的~==

若对技术内容感兴趣可以加入wx群交流:Java高工、架构师3群
若群二维码失效,请加wx号:fsx641385712(或者扫描下方wx二维码)。并且备注:"java入群" 字样,会手动邀请入群

转载于:https://www.cnblogs.com/fangshixiang/p/11261503.html

Apache和Spring提供的StopWatch执行时间监视器相关推荐

  1. Java 统计运行时间之 Apache Commons-lang3和Spring Core提供的StopWatch分析

    前言 编码过程中我们经常会希望得到一段代码(一个方法)的执行时间,本文将介绍两种时间监视器(秒表)来让你优雅的.灵活的处理这个问题. Java源生方式 这种方式最最简单,最好理解,当然也是最为常用:我 ...

  2. Spring的秒表StopWatch优雅的程序计时器 -第455篇

    历史文章(文章累计450+) <国内最全的Spring Boot系列之一> <国内最全的Spring Boot系列之二> <国内最全的Spring Boot系列之三> ...

  3. 【Java】StopWatch任务执行时间监视器

    StopWath是apache commons lang3包下的一个任务执行时间监视器 主要方法:     start();     //开始计时     split();     //设置split ...

  4. Common-lang任务执行时间监视器StopWatch

    StopWath是apache commons lang包下的一个任务执行时间监视器,它可以记录程序从开始执行到结束所花费的时间, 也可以记录程序中的某一段时间差. 主要的方法: start开始计时 ...

  5. Java-利用Spring提供的Resource/ResourceLoader接口操作资源文件

    背景 资源访问接口 主要方法 主要实现类 例子 WritableResource ClassPathResource ServletContextResource 对资源文件编码 资源加载 资源地址表 ...

  6. (转)Spring提供的CharacterEncoding和OpenSessionInView功能

    http://blog.csdn.net/yerenyuan_pku/article/details/52902282 前面我们以一种更加优雅的方式集成了Spring4.2.5+Hibernate4. ...

  7. 发送邮件的JavaMail和Spring提供的MailSender比较分析

    发邮件,项目的必备功能之一,如果一个稍微模块化一点的公司,一般会单独出来一个项目专用来做公司的发送信息的功能,当然这个发送信息中不止包含发邮件,还会有短信.APP push等.这篇聊聊推送邮件. 在以 ...

  8. spring: 使用Spring提供的JDBC模板(使用profiles选择数据源/使用基于JDBC驱动的数据源)...

    Spring提供的JDBC框架负责管理资源和异常处理,从而可以简化开发者的JDBC代码.开发者只需要编写写入和读取数据库相关的代码即可. 正如在之前的小节中论述过的,Spring将数据库访问过程中的模 ...

  9. 给容器中注册组件 || @Scope -- @Lazy -- @Conditional({Condition}) -- @Import--使用Spring提供的 FactoryBean

    * @Scope:调整作用域    * prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中.       *              每次获取的时候才会调用方法创建对象: ...

最新文章

  1. ROI区域提取(图上直接利用鼠标事件提取坐标点,可视化显示)
  2. 【Android】实验3 颜色、字符串资源的使用【提交截止时间:2016.4.1】
  3. php try 错误_PHP异常和错误(2)异常的基本处理:try
  4. 如何避免学习linux必然会遇到的几个问题
  5. 手机拍照普及,相机依然拥有不可替代的优势
  6. shader篇-渲染纹理
  7. 净重新分类指数NRI的计算
  8. C++-Cmake指令:cmake_minimum_required
  9. 基于百度AI平台的植物识别系统 新手适用!!
  10. 【图像处理】相机成像原理
  11. 元宇宙浪潮下,数智人拒绝“标品”
  12. 自动化测试最佳实践(一):从纺锤模型到金字塔模型
  13. BitTorrent协议规范(二)
  14. Cesium 笛卡尔坐标系转经纬度高程
  15. nodejs程序之后台启动forever如何使用json文件格式后台启动多个文件一键管理总结
  16. java ee 与se区别_Java SE和Java EE之间的主要区别是什么?
  17. 2018 年一月联考逻辑真题
  18. DP32G003一款低成本国产单片机
  19. 在WORD中自动生成目录,页码
  20. 用cld和rep movsb以字节传送数据

热门文章

  1. http各个状态码的含义:
  2. 图学习02—图神经网络的发展
  3. Linux网卡重命名规则
  4. 达人评测 R7 PRO 6850HS 核显相当于什么显卡
  5. stata学习笔记(六):数据合并
  6. Pix2Text (P2T) 新版发布,离Mathpix又近了一大步
  7. 5499元起iPhone11来了,发布会全解析,你看值得吗?
  8. php 函数索引 中文索引
  9. BoCloud花磊:专注金融IT架构的变革
  10. linux中的head 显示文件头部内容、tail 输出文件尾部内容