jmh比手写system.currenttimemillis()更准确,可规避jit预热、死码消除等干扰;需用@state、@fork、@warmup、@measurement注解配置,并严格区分int与integer累加逻辑以隔离装箱影响。

直接用 JMH(Java Microbenchmark Harness)写基准测试,比手写 System.currentTimeMillis() 准确得多——它能规避 JIT 预热、死码消除、循环优化等干扰,测出真实差异。
用 JMH 搭建可复现的对比测试
先引入 JMH 依赖(Maven):
<dependency><groupid>org.openjdk.jmh</groupid><artifactid>jmh-core</artifactid><version>1.37</version></dependency>
然后定义一个基准类,聚焦 int 与 Integer 的累加场景(其他类型同理可扩展):
- 标注
@State(Scope.Benchmark)管理共享状态 - 用
@Fork(3)运行 3 轮独立 JVM 实例,降低噪声 - 设
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)充分预热 JIT - 设
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)多次采样取均值
关键测试逻辑要隔离装箱干扰
避免自动装箱污染结果。下面两个方法必须严格区分:
-
基本类型版本:全程使用
int,无对象创建、无拆装箱 -
包装类版本:显式用
Integer.valueOf(i)替代new Integer(i),复用缓存;但累加过程仍会触发隐式拆箱+装箱(sum += i→ 拆sum为int,相加后装箱新Integer)
示例核心方法:
@Benchmark
public int primitiveSum() {
int sum = 0;
for (int i = 0; i
<h3>横向扩展到全部 8 种类型</h3>
<p>按相同模式覆盖所有基本类型及其包装类:</p>
-
byte/Byte、short/Short:注意循环变量和累加器用对应类型,避免隐式提升 -
long/Long:性能差距最显著(64 位值 + 更大对象头),建议单独重点测 -
float/Float、double/Double:浮点运算本身开销大,装箱放大效应更明显 -
char/Character、boolean/Boolean:虽不常用于计算,但集合存取、序列化中高频出现,适合测ArrayList插入/遍历耗时
例如测 Boolean 在集合中的开销:
@Benchmark
public boolean primitiveBoolArray() {
boolean[] arr = new boolean[100_000];
for (int i = 0; i list = new ArrayList(100_000);
for (int i = 0; i
<h3>运行与解读结果的关键细节</h3>
<p>执行 <code>mvn clean compile exec:java -Dexec.mainClass="org.openjdk.jmh.Main" -Dexec.args=".*YourBenchmark.*"</code> 后,关注输出中的:</p>
-
Score ± Error(单位:ns/op):每操作纳秒数,越小越好;
Integer通常比int高 5–10 倍 - Mode = avgt:平均时间模式,排除异常值
-
Gc.alloc.rate.norm:每操作分配字节数,
Integer版本会显示约 24 字节/次(HotSpot 64 位对象开销),int为 0
若发现 Integer 测试结果异常快,检查是否误用了 -128~127 小范围值——此时 valueOf 缓存复用掩盖了真实开销,应改用 1000 或 10000 等超出缓存的值再测。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











