为获得更好的阅读体验,请访问原文:传送门

前言: 最近公司来了个大佬,从他那里学到不少东西,其中一个就是计时

的新姿势「StopWatch」,赶紧来一起了解了解吧!

一、最简单的计时


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

  1. public static void main(String[] args) {
  2. Long startTime = System.currentTimeMillis();
  3. doSomeThing();
  4. Long endTime = System.currentTimeMillis();
  5. Long elapsedTime = (endTime - startTime) / 1000;
  6. System.out.println("总共耗时:" + elapsedTime + "s");
  7. }
  8. // 用于模拟一些操作
  9. private static void doSomeThing() {
  10. try {
  11. Thread.sleep(1000);
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }
  15. }

事实上这样也并没有什么问题,并且也能够运行的很好,但是有一点不太好的就是,自己关注了太多输出的信息,下面我们来认识一种更优雅的一种计时方式;

二、StopWatch 类


想要使用它,首先你需要在你的 Maven 中引入 Spring 核心包,当然 Spring MVC 和 Spring Boot 都已经自动引入了该包:

  1. <!-- spring核心包 -->
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-core</artifactId>
  5. <version>${spring.version}</version>
  6. </dependency>

现在我们计时的姿势或许就会变成以下这样:

  1. public static void main(String[] args) {
  2. StopWatch clock = new StopWatch();
  3. clock.start("开始任务一");
  4. doSomeThing();
  5. clock.stop();
  6. clock.start("开始任务二");
  7. doSomeThing();
  8. clock.stop();
  9. System.out.println(clock.prettyPrint());
  10. }
  11. // 用于模拟一些操作
  12. private static void doSomeThing() {
  13. try {
  14. Thread.sleep(1000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. }

在最后我们使用 StopWatch 类自带的 prettyPrint() 方法类格式化我们的输出,运行程序你会发现你的程序输出了这样的东西:

  1. StopWatch '': running time (millis) = 2009
  2. -----------------------------------------
  3. ms % Task name
  4. -----------------------------------------
  5. 01005 050% 开始任务一
  6. 01004 050% 开始任务二

不仅有总用时,还有每个任务分别的占用时间和占用时间的百分比,这或许就会比我们自己输出要优雅那么一些;

StopWatch 类是怎么实现的呢?

当你戳开 StopWatch 的源码,你会在总共不到 200 行的代码里看到熟悉的东西:

  1. public void start(String taskName) throws IllegalStateException {
  2. if (this.currentTaskName != null) {
  3. throw new IllegalStateException("Can't start StopWatch: it's already running");
  4. } else {
  5. this.currentTaskName = taskName;
  6. this.startTimeMillis = System.currentTimeMillis();
  7. }
  8. }
  9. public void stop() throws IllegalStateException {
  10. if (this.currentTaskName == null) {
  11. throw new IllegalStateException("Can't stop StopWatch: it's not running");
  12. } else {
  13. long lastTime = System.currentTimeMillis() - this.startTimeMillis;
  14. this.totalTimeMillis += lastTime;
  15. this.lastTaskInfo = new StopWatch.TaskInfo(this.currentTaskName, lastTime);
  16. if (this.keepTaskList) {
  17. this.taskList.add(this.lastTaskInfo);
  18. }
  19. ++this.taskCount;
  20. this.currentTaskName = null;
  21. }
  22. }

你会发现该类使用 LinkedList 实现了一个叫做 taskList 的队列,然后每一次开始同样也是使用 System.currentTimeMillis() 方法来获取时间,每次除了计算耗时也会构建一个描述当前任务的 TaskInfo 对象,并把它放入 taskList 队列中。

当执行 prettyPrint() 方法的时候,就从 taskList 队列中依次取出任务,然后做些格式化的操作:

  1. public String shortSummary() {
  2. return "StopWatch '" + this.getId() + "': running time (millis) = " + this.getTotalTimeMillis();
  3. }
  4. public String prettyPrint() {
  5. StringBuilder sb = new StringBuilder(this.shortSummary());
  6. sb.append('\n');
  7. if (!this.keepTaskList) {
  8. sb.append("No task info kept");
  9. } else {
  10. sb.append("-----------------------------------------\n");
  11. sb.append("ms % Task name\n");
  12. sb.append("-----------------------------------------\n");
  13. NumberFormat nf = NumberFormat.getNumberInstance();
  14. nf.setMinimumIntegerDigits(5);
  15. nf.setGroupingUsed(false);
  16. NumberFormat pf = NumberFormat.getPercentInstance();
  17. pf.setMinimumIntegerDigits(3);
  18. pf.setGroupingUsed(false);
  19. StopWatch.TaskInfo[] var4 = this.getTaskInfo();
  20. int var5 = var4.length;
  21. for(int var6 = 0; var6 < var5; ++var6) {
  22. StopWatch.TaskInfo task = var4[var6];
  23. sb.append(nf.format(task.getTimeMillis())).append(" ");
  24. sb.append(pf.format(task.getTimeSeconds() / this.getTotalTimeSeconds())).append(" ");
  25. sb.append(task.getTaskName()).append("\n");
  26. }
  27. }
  28. return sb.toString();
  29. }

摁,新姿势 get √。


按照惯例黏一个尾巴:

欢迎转载,转载请注明出处!

独立域名博客:wmyskxz.com

简书ID:@我没有三颗心脏

github:wmyskxz

欢迎关注公众微信号:wmyskxz

分享自己的学习 & 学习资料 & 生活

想要交流的朋友也可以加qq群:3382693

Java计时新姿势的更多相关文章

  1. Python一键转Jar包,Java调用Python新姿势!

    粉丝朋友们,不知道大家看故事看腻了没(要是没腻可一定留言告诉我^_^),今天这篇文章换换口味,正经的来写写技术文.言归正传,咱们开始吧! 本文结构: 需求背景 进击的Python Java和Pytho ...

  2. Java 8新特性之旅:使用Stream API处理集合

    在这篇“Java 8新特性教程”系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值. 在之前的文章“遍历.过滤.处理集合及使用Lambda ...

  3. 最通俗易懂的 Java 11 新特性讲解

    大多数开发者还是沉浸在 Java 8 中,而 Java 14 将要在 2020 年 3 月 17 日发布了,而我还在写着 Java 11 的新特性.Java 11 是 Java 8 之后的第一个 LT ...

  4. Java 8新特性-4 方法引用

    对于引用来说我们一般都是用在对象,而对象引用的特点是:不同的引用对象可以操作同一块内容! Java 8的方法引用定义了四种格式: 引用静态方法     ClassName :: staticMetho ...

  5. Java 8新特性终极指南

    目录结构 介绍 Java语言的新特性 2.1 Lambdas表达式与Functional接口 2.2 接口的默认与静态方法 2.3 方法引用 2.4 重复注解 2.5 更好的类型推测机制 2.6 扩展 ...

  6. Spring 4支持的Java 8新特性一览

    有众多新特性和函数库的Java 8发布之后,Spring 4.x已经支持其中的大部分.有些Java 8的新特性对Spring无影响,可以直接使用,但另有些新特性需要Spring的支持.本文将带您浏览S ...

  7. Atitit  java jsp 新的tag技术

    Atitit  java jsp 新的tag技术 1.1.  Tag Files  vs 原生写 SimpleTag 比较麻烦的 JSP 1.x 允许 Web 开发人员创建 Java 组件(称为标记处 ...

  8. java 8 新特性

    最近在IDEA的️驱使下,看了点java8的东西,链接贴一下,,,,, 1.Java 8新特性概述2.Java 8中的 Stream API 详解[3.Java 8新特性终极指南] 简单的使用看完新特 ...

  9. 【转+自己研究】新姿势之Docker Remote API未授权访问漏洞分析和利用

    0x00 概述 最近提交了一些关于 docker remote api 未授权访问导致代码泄露.获取服务器root权限的漏洞,造成的影响都比较严重,比如 新姿势之获取果壳全站代码和多台机器root权限 ...

随机推荐

  1. kubernetes实战篇之创建密钥自动拉取私服镜像

    系列目录 前面我们讲解了如何搭建nexus服务器,以及如何使用nexus搭建docker私有镜像仓库,示例中我们都是手动docker login登陆私服,然后通过命令拉取镜像然后运行容器.然而这种做法 ...

  2. 微服务网关 Spring Cloud Gateway

    1.  为什么是Spring Cloud Gateway 一句话,Spring Cloud已经放弃Netflix Zuul了.现在Spring Cloud中引用的还是Zuul 1.x版本,而这个版本是 ...

  3. Python笔记【7】_反射getattr&hasattr&setattr&delattr

    Lesson0402_GetatrrWebsite.py #!/usr/bin/env/python #-*-coding:utf-8-*- #Author:LingChongShi #查看源码Ctr ...

  4. 另一个ACM之路建议

    ACM联系建议 一位高手对我的建议: 一般要做到50行以内的程序不用调试.100行以内的二分钟内调试成功.acm主要是考算法的 ,主要时间是花在思考算法上,不是花在写程序与debug上. 下面给个计划 ...

  5. Netty源码分析-- 处理客户端接入请求(八)

    这一节我们来一起看下,一个客户端接入进来是什么情况.首先我们根据之前的分析,先启动服务端,然后打一个断点. 这个断点打在哪里呢?就是NioEventLoop上的select方法上. 然后我们启动一个客 ...

  6. 浅谈Invoke 和 BegionInvoke的用法

    很多人对Invoke和BeginInvoke理解不深刻,不知道该怎么应用,在这篇博文里将详细阐述Invoke和BeginInvoke的用法: 首先说下Invoke和BeginInvoke有两种用法: ...

  7. leadcode的Hot100系列--62. 不同路径--简单的动态规划

    题目比较清晰,简单来说就是: A B C D E F G H I J K L 只能往右或者往下,从A到L,能有几种走法. 这里使用动态规划的方法来做一下. 动态规划最重要的就是动态方程,这里简单说下这 ...

  8. POJ 1741:Tree(树上点分治)

    题目链接 题意 给一棵边带权树,问两点之间的距离小于等于K的点对有多少个. 思路 <分治算法在树的路径问题中的应用> 图片转载于http://www.cnblogs.com/Paul-Gu ...

  9. cookie 和 session 设置

    cookie: 保存在浏览器上的一组键值对, 是由服务器让浏览器进行设置的 下次浏览器访问的时候会携带cookie. request是客户端请求, response是服务端响应. 读取客户端的cook ...

  10. Spring Cloud Alibaba | 序言

    目录 Spring Cloud Alibaba | 序言 1. Spring Cloud Alibaba是什么? 2. 主要功能 3. 组件 4. 版本说明 4.1 版本依赖关系 4.2 组件版本关系 ...