You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何计算执行时间?为何相同示例多次运行结果存在差异?

为什么同一算法的执行时间差异明显?怎么精准测量?

这是性能测试里非常常见的问题,我来帮你理清楚原因和靠谱的解决办法~

为什么单次执行时间波动大?

你遇到的23-29ms的波动,主要是这些因素导致的:

  • 操作系统线程调度:你的Java进程随时可能被操作系统暂停,让给其他后台进程(比如杀毒软件、系统更新、浏览器等),这部分等待时间会被算进你的计时里,每次暂停的时长都不一样。
  • JVM即时编译(JIT):Java代码一开始是解释执行的,JVM会把频繁执行的热点代码编译成机器码(这个过程叫JIT编译)。前几次执行bm.search时可能还没完成编译,速度慢;后面编译完成后速度会提升,时间自然就不一样了。
  • CPU缓存效应:第一次执行时,你的测试文本和模式串可能还不在CPU的高速缓存里,需要从内存加载,速度慢;后面再执行时数据已经在缓存里,访问速度快很多,时间就变短了。
  • 其他系统干扰:比如后台突然跑个磁盘IO任务、网络请求,都会抢占系统资源,影响你的程序执行速度。

更精准可靠的计算方法

针对这些问题,有几个实用的解决方案:

1. 先预热代码,再多次执行取统计值

自己写代码的话,先执行几次搜索让JVM完成JIT编译和缓存加载,然后执行几十上百次,取平均值或者中位数(中位数更能避免极端值的影响):

import java.util.Arrays;

// 预热:先执行10次,让JVM完成编译和缓存加载
for (int i = 0; i < 10; i++) {
    bm.search(mediumtext, mediumpattern);
}

// 正式测试,执行100次
int totalRuns = 100;
long totalNanos = 0;
long[] times = new long[totalRuns];

for (int i = 0; i < totalRuns; i++) {
    long start = System.nanoTime();
    bm.search(mediumtext, mediumpattern);
    long end = System.nanoTime();
    long elapsed = end - start;
    times[i] = elapsed;
    totalNanos += elapsed;
}

// 计算平均值
double avgMs = totalNanos / (1_000_000.0 * totalRuns);
// 计算中位数(简单实现)
Arrays.sort(times);
double medianMs = times[totalRuns / 2] / 1_000_000.0;

System.out.printf("Average time: %.3f ms\n", avgMs);
System.out.printf("Median time: %.3f ms\n", medianMs);

2. 使用专业的微基准测试框架:JMH

如果要做更严谨的性能测试,推荐用OpenJDK的JMH(Java Microbenchmark Harness),它专门为Java微基准测试设计,自动处理预热、避免死码消除、控制执行环境,结果非常可靠。

举个简单的JMH示例:

import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;

// 指定测试模式为平均时间,输出单位为毫秒
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
// 预热5轮,每轮1秒
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
// 正式测试10轮,每轮1秒
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
// fork一个新的JVM进程执行测试,避免其他代码干扰
@Fork(1)
public class BMSearchBenchmark {

    // 提前初始化测试数据,避免每次测试都重复创建
    private static final String MEDIUM_TEXT = "你的测试文本内容";
    private static final String MEDIUM_PATTERN = "你的模式串内容";
    private static final BM BM_INSTANCE = new BM();

    // 被测试的方法,JMH会自动调用这个方法进行测试
    @Benchmark
    public void testBmSearch() {
        BM_INSTANCE.search(MEDIUM_TEXT, MEDIUM_PATTERN);
    }
}

使用JMH需要在项目里添加对应依赖(比如Maven/Gradle),然后通过JMH插件运行,它会输出详细的统计结果,包括平均值、误差范围等,比手动实现的测试严谨得多。

内容的提问来源于stack exchange,提问作者user14388485

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:37:44