当前位置: 代码网 > it编程>编程语言>Java > Java统计代码的执行时间的常见方法总结

Java统计代码的执行时间的常见方法总结

2026年05月08日 Java 我要评论
在日常开发中经常需要测试一些代码的执行时间,但又不想使用向 jmh(java microbenchmark harness,java 微基准测试套件)这么重的测试框架,所以本文就汇总了一些 java

在日常开发中经常需要测试一些代码的执行时间,但又不想使用向 jmh(java microbenchmark harness,java 微基准测试套件)这么重的测试框架,所以本文就汇总了一些 java 中比较常用的执行时间统计方法,总共包含以下 6 种,如下图所示:

方法一:system.currenttimemillis

此方法为 java 内置的方法,使用 system#currenttimemillis 来统计执行的时间(统计单位:毫秒),示例代码如下:

public class timeintervaltest {
    public static void main(string[] args) throws interruptedexception {
        // 开始时间
        long stime = system.currenttimemillis();
        // 执行时间(1s)
        thread.sleep(1000);
        // 结束时间
        long etime = system.currenttimemillis();
        // 计算执行时间
        system.out.printf("执行时长:%d 毫秒.", (etime - stime));
    }
}

以上程序的执行结果为:

执行时长:1000 毫秒.

方法二:system.nanotime

此方法为 java 内置的方法,使用 system#nanotime 来统计执行时间(统计单位:纳秒),它的执行方法和 system#currenttimemillis 类似,示例代码如下:

public class timeintervaltest {
    public static void main(string[] args) throws interruptedexception {
        // 开始时间
        long stime = system.nanotime();
        // 执行时间(1s)
        thread.sleep(1000);
        // 结束时间
        long etime = system.nanotime();
        // 计算执行时间
        system.out.printf("执行时长:%d 纳秒.", (etime - stime));
    }
}

以上程序的执行结果为:

执行时长:1000769200 纳秒.
小贴士:1 毫秒 = 100 万纳秒。

方法三:new date

此方法也是 java 的内置方法,在开始执行前 new date() 创建一个当前时间对象,在执行结束之后 new date() 一个当前执行时间,然后再统计两个 date 的时间间隔,示例代码如下:

import java.util.date;

public class timeintervaltest {
    public static void main(string[] args) throws interruptedexception {
        // 开始时间
        date sdate = new date();
        // 执行时间(1s)
        thread.sleep(1000);
        // 结束时间
        date edate = new date();
        //  统计执行时间(毫秒)
        system.out.printf("执行时长:%d 毫秒." , (edate.gettime() - sdate.gettime())); 
    }
}

以上程序的执行结果为:

执行时长:1000 毫秒.

方法四:spring stopwatch

如果我们使用的是 spring 或 spring boot 项目,可以在项目中直接使用 stopwatch 对象来统计代码执行时间,示例代码如下:

stopwatch stopwatch = new stopwatch();
// 开始时间
stopwatch.start();
// 执行时间(1s)
thread.sleep(1000);
// 结束时间
stopwatch.stop();
// 统计执行时间(秒)
system.out.printf("执行时长:%d 秒.%n", stopwatch.gettotaltimeseconds()); // %n 为换行
// 统计执行时间(毫秒)
system.out.printf("执行时长:%d 毫秒.%n", stopwatch.gettotaltimemillis()); 
// 统计执行时间(纳秒)
system.out.printf("执行时长:%d 纳秒.%n", stopwatch.gettotaltimenanos());

以上程序的执行结果为:

执行时长:0.9996313 秒. 执行时长:999 毫秒. 执行时长:999631300 纳秒.
小贴士:thread#sleep 方法的执行时间稍有偏差,在 1s 左右都是正常的。

方法五:commons-lang3 stopwatch

如果我们使用的是普通项目,那我们可以用 apache commons-lang3 中的 stopwatch 对象来实现时间统计,首先先添加 commons-lang3 的依赖:

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
  <groupid>org.apache.commons</groupid>
  <artifactid>commons-lang3</artifactid>
  <version>3.10</version>
</dependency>

然后编写时间统计代码:

import org.apache.commons.lang3.time.stopwatch;

import java.util.concurrent.timeunit;

public class timeintervaltest {
    public static void main(string[] args) throws interruptedexception {
        stopwatch stopwatch = new stopwatch();
        // 开始时间
        stopwatch.start();
        // 执行时间(1s)
        thread.sleep(1000);
        // 结束时间
        stopwatch.stop();
        // 统计执行时间(秒)
        system.out.println("执行时长:" + stopwatch.gettime(timeunit.seconds) + " 秒.");
        // 统计执行时间(毫秒)
        system.out.println("执行时长:" + stopwatch.gettime(timeunit.milliseconds) + " 毫秒.");
        // 统计执行时间(纳秒)
        system.out.println("执行时长:" + stopwatch.gettime(timeunit.nanoseconds) + " 纳秒.");
    }
}

以上程序的执行结果为:

执行时长:1 秒. 执行时长:1000 毫秒.
执行时长:1000555100 纳秒.

方法六:guava stopwatch

除了 apache 的 commons-lang3 外,还有一个常用的 java 工具包,那就是 google 的 guava,guava 中也包含了  stopwatch 统计类。首先先添加 guava 的依赖:

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
  <groupid>com.google.guava</groupid>
  <artifactid>guava</artifactid>
  <version>29.0-jre</version>
</dependency>

然后编写时间统计代码:

import com.google.common.base.stopwatch;

import java.util.concurrent.timeunit;

public class timeintervaltest {
    public static void main(string[] args) throws interruptedexception {
        // 创建并启动计时器
        stopwatch stopwatch = stopwatch.createstarted();
        // 执行时间(1s)
        thread.sleep(1000);
        // 停止计时器
        stopwatch.stop();
        // 执行时间(单位:秒)
        system.out.printf("执行时长:%d 秒. %n", stopwatch.elapsed().getseconds()); // %n 为换行
        // 执行时间(单位:毫秒)
        system.out.printf("执行时长:%d 豪秒.", stopwatch.elapsed(timeunit.milliseconds));
    }
}

以上程序的执行结果为:

执行时长:1 秒.
执行时长:1000 豪秒.

原理分析

本文我们从 spring 和 google 的 guava 源码来分析一下,它们的 stopwatch 对象底层是如何实现的?

1.spring stopwatch 原理分析

在 spring 中 stopwatch 的核心源码如下:

package org.springframework.util;

import java.text.numberformat;
import java.util.linkedlist;
import java.util.list;
import java.util.concurrent.timeunit;
import org.springframework.lang.nullable;

public class stopwatch {
    private final string id;
    private boolean keeptasklist;
    private final list<stopwatch.taskinfo> tasklist;
    private long starttimenanos;
    @nullable
    private string currenttaskname;
    @nullable
    private stopwatch.taskinfo lasttaskinfo;
    private int taskcount;
    private long totaltimenanos;

    public stopwatch() {
        this("");
    }

    public stopwatch(string id) {
        this.keeptasklist = true;
        this.tasklist = new linkedlist();
        this.id = id;
    }

    public string getid() {
        return this.id;
    }

    public void setkeeptasklist(boolean keeptasklist) {
        this.keeptasklist = keeptasklist;
    }

    public void start() throws illegalstateexception {
        this.start("");
    }

    public void start(string taskname) throws illegalstateexception {
        if (this.currenttaskname != null) {
            throw new illegalstateexception("can't start stopwatch: it's already running");
        } else {
            this.currenttaskname = taskname;
            this.starttimenanos = system.nanotime();
        }
    }

    public void stop() throws illegalstateexception {
        if (this.currenttaskname == null) {
            throw new illegalstateexception("can't stop stopwatch: it's not running");
        } else {
            long lasttime = system.nanotime() - this.starttimenanos;
            this.totaltimenanos += lasttime;
            this.lasttaskinfo = new stopwatch.taskinfo(this.currenttaskname, lasttime);
            if (this.keeptasklist) {
                this.tasklist.add(this.lasttaskinfo);
            }

            ++this.taskcount;
            this.currenttaskname = null;
        }
    }
    // .... 忽略其他代码
}

从上述 start() 和 stop() 的源码中可以看出,spring 实现时间统计的本质还是使用了 java 的内置方法 system.nanotime() 来实现的。

2.google stopwatch 原理分析

google stopwatch 实现的核心源码如下:

public final class stopwatch {
    private final ticker ticker;
    private boolean isrunning;
    private long elapsednanos;
    private long starttick;
    @canignorereturnvalue
    public stopwatch start() {
        preconditions.checkstate(!this.isrunning, "this stopwatch is already running.");
        this.isrunning = true;
        this.starttick = this.ticker.read();
        return this;
    }

    @canignorereturnvalue
    public stopwatch stop() {
        long tick = this.ticker.read();
        preconditions.checkstate(this.isrunning, "this stopwatch is already stopped.");
        this.isrunning = false;
        this.elapsednanos += tick - this.starttick;
        return this;
    }
    // 忽略其他源码...
}

从上述源码中可以看出 stopwatch 对象中调用了 ticker 类来实现时间统计的,那接下来我们进入 ticker 类的实现源码:

public abstract class ticker {
    private static final ticker system_ticker = new ticker() {
        public long read() {
            return platform.systemnanotime();
        }
    };
    protected ticker() {
    }
    public abstract long read();
    public static ticker systemticker() {
        return system_ticker;
    }
}
final class platform {
    private static final logger logger = logger.getlogger(platform.class.getname());
    private static final patterncompiler patterncompiler = loadpatterncompiler();

    private platform() {
    }

    static long systemnanotime() {
        return system.nanotime();
    }
    // 忽略其他源码...
}

从上述源码可以看出 google stopwatch 实现时间统计的本质还是调用了 java 内置的 system.nanotime() 来实现的。

结论

对于所有框架的 stopwatch 来说,其底层都是通过调用 java 内置的 system.nanotime() 得到两个时间,开始时间和结束时间,然后再通过结束时间减去开始时间来统计执行时间的。

总结

本文介绍了 6 种实现代码统计的方法,其中 3 种是 java 内置的方法:

  • system.currenttimemillis()
  • system.nanotime()
  • new date()

还介绍了 3 种常用框架 spring、commons-langs3、guava 的时间统计器 stopwatch

在没有用到 spring、commons-langs3、guava 任意一种框架的情况下,推荐使用 system.currenttimemillis() 或 system.nanotime() 来实现代码统计,否则建议直接使用 stopwatch 对象来统计执行时间。

知识扩展—stopwatch 让统计更方便

stopwatch 存在的意义是让代码统计更简单,比如 guava 中 stopwatch 使用示例如下:

import com.google.common.base.stopwatch;

import java.util.concurrent.timeunit;

public class timeintervaltest {
    public static void main(string[] args) throws interruptedexception {
        // 创建并启动计时器
        stopwatch stopwatch = stopwatch.createstarted();
        // 执行时间(1s)
        thread.sleep(1000);
        // 停止计时器
        stopwatch.stop();
        // 执行统计
        system.out.printf("执行时长:%d 毫秒. %n",
                stopwatch.elapsed(timeunit.milliseconds));
        // 清空计时器
        stopwatch.reset();
        // 再次启动统计
        stopwatch.start();
        // 执行时间(2s)
        thread.sleep(2000);
        // 停止计时器
        stopwatch.stop();
        // 执行统计
        system.out.printf("执行时长:%d 秒. %n",
                stopwatch.elapsed(timeunit.milliseconds));
    }
}

我们可以使用一个 stopwatch 对象统计多段代码的执行时间,也可以通过指定时间类型直接统计出对应的时间间隔,比如我们可以指定时间的统计单位,如秒、毫秒、纳秒等类型。

方法补充

在 java 中统计代码执行时间有多种方法,从简单的基础 api 到功能丰富的工具类,各有适用场景。下面介绍几种最常用的方式,并给出示例代码和注意事项。

使用 system.currenttimemillis()(毫秒级)

最简单、最直接的方法,返回当前时间与 1970-01-01 utc 的毫秒差值。

long start = system.currenttimemillis();
// 待测代码
thread.sleep(100);
long end = system.currenttimemillis();
system.out.println("执行耗时:" + (end - start) + " ms");

优点

  • 简单易用,无需额外依赖。
  • 适合粗略测量(毫秒级精度)。

缺点

  • 受系统时间调整影响(如手动修改系统时间会导致结果错误)。
  • 精度有限(毫秒级,无法测量极短时间)。

使用 system.nanotime()(纳秒级,推荐)

返回正在运行的 java 虚拟机的高精度时间源,不受系统时间调整影响,适合测量短时间间隔。

long start = system.nanotime();
// 待测代码
thread.sleep(100);
long end = system.nanotime();
system.out.println("执行耗时:" + (end - start) / 1_000_000.0 + " ms");

优点

  • 高精度(通常可达纳秒级)。
  • 不受系统时钟修改影响,是测量代码执行时间的首选

缺点:不能用于计算绝对时间(只适合测量时间差)。

使用 instant 与 duration(java 8+,更可读)

使用 java.time.instant 记录时间点,java.time.duration 计算差值。

import java.time.duration;
import java.time.instant;
instant start = instant.now();
// 待测代码
thread.sleep(100);
instant end = instant.now();
duration duration = duration.between(start, end);
system.out.println("执行耗时:" + duration.tomillis() + " ms");

优点

  • 代码语义清晰,可读性好。
  • duration 提供丰富的单位转换(纳秒、毫秒、秒等)。

缺点:底层依赖系统时钟,与 system.currenttimemillis() 类似,受系统时间调整影响。

使用 spring 的 stopwatch(方便管理多个任务)

若项目中已使用 spring,可以利用 org.springframework.util.stopwatch,支持多任务计时、漂亮输出。

import org.springframework.util.stopwatch;
stopwatch stopwatch = new stopwatch();
stopwatch.start("task1");
// 任务1代码
thread.sleep(100);
stopwatch.stop();
stopwatch.start("task2");
// 任务2代码
thread.sleep(50);
stopwatch.stop();
system.out.println(stopwatch.prettyprint());

输出示例:

stopwatch '': running time = 150 ms
---------------------------------------------
ms     %     task name
---------------------------------------------
00100  067%  task1
00050  033%  task2

优点

  • 支持多个任务、任务名、分阶段统计。
  • 输出格式美观,适合性能分析。

缺点:需要引入 spring 框架(或单独使用 spring-core)。

使用 apache commons lang 的 stopwatch

不依赖 spring 时可使用 apache commons lang 3 的 stopwatch

import org.apache.commons.lang3.time.stopwatch;
stopwatch watch = new stopwatch();
watch.start();
// 待测代码
thread.sleep(100);
watch.stop();
system.out.println("耗时:" + watch.gettime() + " ms");

优点

  • 轻量级,仅依赖 commons-lang3
  • 支持 split()suspend() 等更细粒度的控制。

缺点:需要额外引入依赖。

jmh(java microbenchmark harness)—— 专业的基准测试工具

当需要精准、可靠地测量微秒级性能、避免 jvm 优化干扰时,应使用 jmh。例如测试某个算法的吞吐量。

import org.openjdk.jmh.annotations.*;
@state(scope.thread)
@benchmarkmode(mode.averagetime)
@outputtimeunit(timeunit.nanoseconds)
public class mybenchmark {
    @benchmark
    public void testmethod() {
        // 待测代码
    }
}

运行方式:

mvn clean install
java -jar target/benchmarks.jar

优点

  • 自动处理 jvm 预热、死代码消除、黑盒优化等问题。
  • 提供多种测量模式(吞吐量、平均时间、采样时间等)。
  • 结果统计信息全面(均值、误差、百分位数等)。

缺点

  • 学习曲线较陡,配置相对复杂。
  • 不适合简单的“一次性”计时。

总结与对比

方法精度是否受系统时间调整适用场景
system.currenttimemillis()毫秒粗略测量,简单日志
system.nanotime()纳秒(高精度)绝大多数计时需求推荐
instant + duration毫秒(实际同系统时间)追求可读性,且不受系统时间影响不重要时
spring stopwatch毫秒否(使用nanotime多任务分段计时,输出美观
apache commons stopwatch毫秒轻量级,需要额外库
jmh极高(纳秒级)微基准测试,jvm 性能调优

最佳实践

  • 对于单元测试或简单性能日志,使用 system.nanotime() 即可满足绝大部分需求。
  • 若需要同时测量多个阶段或输出美观报告,选用 spring 或 apache commons 的 stopwatch
  • 编写正式的性能基准(如方法优化对比),务必使用 jmh,避免 jvm 优化带来的虚假结果。

最后,测量代码执行时间时,要注意:

  • jvm 存在预热(just-in-time 编译),第一次执行往往较慢,建议多次运行取平均值。
  • 测量时间过短的代码(< 1ms)容易受操作系统线程调度影响,应循环多次测量并求平均。

以上就是java统计代码的执行时间的常见方法总结的详细内容,更多关于java统计代码执行时间的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com