Java计时新姿势StopWatch的使用方法详解

目录
  • 一、背景
  • 二、spring 用法
    • 2.1 初遇
    • 2.2 源码
    • 2.3 注意事项
  • 三、apache 用法
  • 四、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.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后它的值为null
    System.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");
    // 直接转成s
    System.out.println("花费的时间》》" + watch.getTime(TimeUnit.SECONDS) + "s");
}

四、java 中使用StopWatch来计算时间差

以前在进行时间耗时时我们通常的做法是先给出计算前后两个的时间值,然后通过详见来计算耗时时长。

eg:

long start = System.currentTimeMillis();
......业务处理
System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");

我们可以使用已有的工具类中的秒表来替代上述的使用方式,现有的秒表工具类有org.springframework.util.StopWatch、org.apache.commons.lang.time.StopWatch,这里以Spring的StopWatch类为例:

public static void main(String[] args) throws InterruptedException{

        StopWatch stopWatch = new StopWatch("任务耗时秒表工具");

        stopWatch.start("task1");
        Thread.sleep(1000);
        stopWatch.stop();
        System.out.println(stopWatch.getTotalTimeMillis());
        stopWatch.start("task2");
        Thread.sleep(3000);
        stopWatch.stop();
        //所有任务耗时时间
        System.out.println(stopWatch.getTotalTimeMillis());
        System.out.println(stopWatch.prettyPrint());

        StopWatch stopWatch2 = new StopWatch("任务耗时秒表工具2");
        stopWatch2.start("task3");
        Thread.sleep(3000);
        stopWatch2.stop();
        //所有任务耗时时间
        System.out.println(stopWatch2.getTotalTimeMillis());
        System.out.println(stopWatch2.prettyPrint());

    }

五、最后

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

到此这篇关于Java计时新姿势StopWatch使用的文章就介绍到这了,更多相关Java计时StopWatch内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java Stopwatch类,性能与时间计时器案例详解

    在研究性能的时候,完全可以使用Stopwatch计时器计算一项技术的效率.但是有时想知道某想技术的性能的时候,又常常想不起可以运用Stopwatch这个东西,太可悲了. 属性: Elapsed 获取当前实例测量得出的总运行时间. ElapsedMilliseconds  获取当前实例测量得出的总运行时间(以毫秒为单位). ElapsedTicks  获取当前实例测量得出的总运行时间(用计时器计时周期表示). IsRunning   获取一个指示 Stopwatch 计时器是否在运行的值. 方法

  • Java计时新姿势StopWatch详解

    一.最简单的计时 在我们的程序中不免需要对某一个运算或者方法进行计时,以便我们来观察该运算或方法是否符合我们的预期,所以在我们刚开始接触 Java 的时候都能写出类似下面这样的代码来计时: public static void main(String[] args) { Long startTime = System.currentTimeMillis(); doSomeThing(); Long endTime = System.currentTimeMillis(); Long elapse

  • Java计时器StopWatch实现方法代码实例

    下面提供三种计时器的写法供大家参考,大家可以自行选择自己钟爱的使用. 写法一(Spring 包提供的计时器): import java.text.NumberFormat; import java.util.LinkedList; import java.util.List; /** * Simple stop watch, allowing for timing of a number of tasks, * exposing total running time and running ti

  • Java计时新姿势StopWatch的使用方法详解

    目录 一.背景 二.spring 用法 2.1 初遇 2.2 源码 2.3 注意事项 三.apache 用法 四.java 中使用StopWatch来计算时间差 五.最后 一.背景 有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,一般我们检测某段代码执行的时间,都是以如下方式来进行的: public static void main(String[] args) { Long startTime = System.curr

  • Java唤醒本地应用的两种方法详解

    目录 引言 1. Runtime使用方式 2. ProcessBuilder使用方式 3. 小结 引言 作为一个后端同学,经常被安全的小伙伴盯上,找一找安全漏洞:除了常说的注入之外,还有比较吓人的执行远程命令,唤醒本地应用程序等:然后有意思的问题就来了,写了这么多年的代码,好像还真没有尝试过用java来唤醒本地应用程序的 比如说一个最简单的,打开本地的计算器,应该怎么搞? 接下来本文将介绍一下如何使用java打开本地应用,以及打开mac系统中特殊一点的处理方式(直白来说就是不同操作系统,使用姿势

  • Java 添加超链接到 Word 文档方法详解

    在Word文档中,超链接是指在特定文本或者图片中插入的能跳转到其他位置或网页的链接,它也是我们在编辑制作Word文档时广泛使用到的功能之一.今天这篇文章就将为大家演示如何使用Free Spire.Doc for Java在Word文档中添加文本超链接和图片超链接. Jar包导入 方法一:下载Free Spire.Doc for Java包并解压缩,然后将lib文件夹下的Spire.Doc.jar包作为依赖项导入到Java应用程序中. 方法二:通过Maven仓库安装JAR包,配置pom.xml文件

  • Java Fluent Mybatis 聚合查询与apply方法详解流程篇

    前言 接着上一篇文章:Java Fluent Mybatis 分页查询与sql日志输出详解流程篇 我把分页已经调整好了,现在实验一下官方给出的聚合查询方法. GitHub代码仓库:GitHub仓库 数据准备 为了聚合查询的条件,添加了几条数据. MIN 我们试着获取最小的年龄. 方法实现 @Override public Integer getAgeMin() { Map<String, Object> result = testFluentMybatisMapper .findOneMap(

  • Java JWT实现跨域身份验证方法详解

    目录 1.JWT简介 2.JWT的结构 2.1 头部(header) 2.2 载荷(payload) 2.3 签证(signature) 3.JWT的原则 4.JWT的用法 5.JWT的问题和趋势 6.整合JWT令牌 6.1 在模块中添加jwt工具依赖 6.2 创建JWT工具类 1.JWT简介 JWT(JSON Web Token)是目前流行的跨域认证解决方案,是一个开放标准(RFC 7519),它定义了一种紧凑的.自包含的方式,用于作为JSON对象在各方之间安全地传输信息.该信息可以被验证和信

  • Java实现字符串转为驼峰格式的方法详解

    字符串转为驼峰格式 构建工具类 package com.yt.common.util; import com.yt.common.dto.NameCode; import com.yt.exam.enums.ZyEnum; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 字符串转为驼峰格式 构建工具类 * @author LYY * @date 2022/07

  • Java实现API sign签名校验的方法详解

    目录 1. 前言 2. 签名生成策略 3. API 签名算法 Java 实现 4. 测试一下 1. 前言 目的:为防止中间人攻击. 场景: 项目内部前后端调用,这种场景只需要做普通参数的签名校验和过期请求校验,目的是为了防止攻击者劫持请求 url 后非法请求接口. 开放平台向第三方应用提供能力,这种场景除了普通参数校验和请求过期校验外,还要考虑 3d 应用的授权机制,不被授权的应用就算传入了合法的参数也不能被允许请求成功. 2. 签名生成策略 接下来详述场景 2,其实场景 1 也包含在场景 2

  • Java利用位运算实现加减乘除的方法详解

    目录 前言 一.常见位运算 1. &运算 2. |运算 3. ^运算 4. ~运算 二.位运算实现加法 三.位运算实现减法 四.位运算实现乘法 五.位运算实现除法 前言 我们经常使用的加减乘除,我们所看到的只是表面的效果,那么加减乘除在底层究竟是怎么实现的?今天就让我们一探究竟.今天用位运算实现的加减乘除不使用任何的加减乘除符号. 一.常见位运算 1. &运算 &运算二进制每一位全1为1,否则为0 public static void main(String[] args) { i

  • Java使用POI实现导出Excel的方法详解

    目录 一.前景 二.概念 2.1. 简介 2.2.Excel版本和相关对象 2.3.WorkBook 2.4.POI依赖 三.POI - 写 3.1.代码示例 3.2. 性能对比 3.3. 测试rowAccessWindowSize 3.4. 导出Excel样式设置 四.POI - 读 4.1.代码示例 4.2.读取不同的数据类型 4.3.读取公式 五.POI - 遇到的坑 一.前景 在项目开发中往往需要使用到Excel的导入和导出,导入就是从Excel中导入到DB中,而导出就是从DB中查询数据

随机推荐