JHM是openJDK开发的一个benchmark框架。它是一个Maven依赖,所以创建一个Maven项目,引入下面两个依赖:

    <dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.37</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.37</version>
</dependency>

两个依赖版本一样,版本号你可以去中心仓库查一下最新的,目前是1.37

然后就可以写一个测试类,比如我想对比一下ArrayListLinkedList哪个性能好:

你猜哪个性能好?你可能会说给中间插入值链表更快,但是怎么知道插入到哪里呢...

基准配置

我的测试类叫MyBenchmark,在main方法中配置如下:

    public static void main(String[] args) throws RunnerException {
System.out.println("Hello World!");
Options options = new OptionsBuilder()
.include(MyBenchmark.class.getSimpleName())
// 这里需要include测试类进来,使用simpleName就行
.forks(1)
// forks是启动几个JVM实例,每个实例单独测试,配置1就行
.timeout(TimeValue.seconds(10))
// timeout指定下面配置的每一次测试的超时时间,你可以改大一些
.threads(1)
// 线程数是同时用几个线程跑测试代码,比如我的笔记本是6核12线程的,3线程反而最好
.warmupIterations(1)
// 正式测试前跑几次热身。和正式测试流程一样,只是数据不计入统计结果
.warmupTime(TimeValue.seconds(10))
// 预热多久
.measurementTime(TimeValue.seconds(2))
// 正式测试每次多久
.measurementIterations(5)
// 测试几轮
.build(); new Runner(options).run();
}

Round One

第一轮测试代码如下:


public class MyBenchmark {
private static final int limit = 10_0000;
@Benchmark
public void testArrayList() {
List<Integer> list = new ArrayList<>(1);
for (int i = 0; i < limit; i++) {
list.add(i);
}
if (false) {
System.out.println("more");
}
} @Benchmark
public void testLinkedList() {
List<Integer> list = new LinkedList<>();
for (int i = 0; i < limit; i++) {
list.add(i);
}
if (false) {
System.out.println("more");
}
}
}

给每个集合中加入10万个数,看每秒能执行多少次。你先猜一下结果。

执行main方法,会打印出配置信息,比如

# JMH version: 1.37
# VM version: JDK 21.0.1, Java HotSpot(TM) 64-Bit Server VM, 21.0.1+12-jvmci-23.1-b19
# VM invoker: /.sdkman/candidates/java/21.0.1-graal/bin/java
# VM options: -XX:ThreadPriorityPolicy=1 -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCIProduct -XX:-UnlockExperimentalVMOptions -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=53238:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 1 iterations, 10 s each
# Measurement: 5 iterations, 2 s each
# Timeout: 10 s per iteration, ***WARNING: The timeout might be too low!***
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time

测试结果:

Benchmark                    Mode  Cnt     Score      Error  Units
MyBenchmark.testArrayList thrpt 5 1286.969 ± 1686.876 ops/s
MyBenchmark.testLinkedList thrpt 5 1909.538 ± 373.143 ops/s

数组每秒1000多次(每次插入10万数据),链表每秒快2000次了。链表取胜!

如果数据改成1000个,结果是

Benchmark                    Mode  Cnt       Score       Error  Units
MyBenchmark.testArrayList thrpt 5 174194.500 ± 19431.634 ops/s
MyBenchmark.testLinkedList thrpt 5 169880.651 ± 74638.041 ops/s

数组险胜。

Round Two

这次把其中的操作改成排序,每插入一个数就进行一个倒序排序:

            list.add(i);
list.sort(Comparator.reverseOrder());// 使用逆序,让他一定要移动数据

你猜结果如何?

先看1万个数据(10万的话我电脑可能完不成):

Benchmark                    Mode  Cnt  Score   Error  Units
MyBenchmark.testArrayList thrpt 5 4.867 ± 2.272 ops/s
MyBenchmark.testLinkedList thrpt 5 0.638 ± 1.323 ops/s

数组完胜!

再看100个数据:

Benchmark                    Mode  Cnt      Score       Error  Units
MyBenchmark.testArrayList thrpt 5 79449.678 ± 97210.639 ops/s
MyBenchmark.testLinkedList thrpt 5 32889.346 ± 2018.265 ops/s

数组还是比链表优势大很多。

Round Three

这次往中间插入值:

            list.add(i/2, 1);
// list.sort(Comparator.reverseOrder());

看10万数据的结果就行了,你猜结果啥样:

Benchmark                    Mode  Cnt  Score   Error  Units
MyBenchmark.testArrayList thrpt 5 3.606 ± 2.153 ops/s
MyBenchmark.testLinkedList thrpt 5 0.151 ± 0.112 ops/s

不说了,我要去删掉我之前代码中的链表了。

java中的基准测试框架JMH的更多相关文章

  1. 如何在Java中做基准测试?JMH使用初体验

    大家好,我是王有志,欢迎和我聊技术,聊漂泊在外的生活.快来加入我们的Java提桶跑路群:共同富裕的Java人. 最近公司在搞新项目,由于是实验性质,且不会直接面对客户的项目,这次的技术选型非常激进,如 ...

  2. 菜鸟日记之 java中的集合框架

    java中的集合框架图 如图所示:java中的集合分为两种Collection和Map两种接口 可分为Collection是单列集合和Map的双列集合 Collection单列集合:继承了Iterat ...

  3. Java中的集合框架(上)

    Java中的集合框架概述 集合的概念: Java中的集合类:是一种工具类,就像是容器,存储任意数量的具有共同属性的对象. 集合的作用: 1.在类的内部,对数据进行组织: 2.简单的快速的搜索大数据量的 ...

  4. Java中的集合框架-Collections和Arrays

    上一篇<Java中的集合框架-Map>把集合框架中的键值对容器Map中常用的知识记录了一下,本节记录一下集合框架的两个工具类Collections和Arrays 一,Collections ...

  5. Java中的集合框架-Map

    前两篇<Java中的集合框架-Commection(一)>和<Java中的集合框架-Commection(二)>把集合框架中的Collection开发常用知识点作了一下记录,从 ...

  6. Java中的集合框架-Collection(二)

    上一篇<Java中的集合框架-Collection(一)>把Java集合框架中的Collection与List及其常用实现类的功能大致记录了一下,本篇接着记录Collection的另一个子 ...

  7. Java中的集合框架

    概念与作用 集合概念 现实生活中:很多事物凑在一起 数学中的集合:具有共同属性的事物的总体 java中的集合类:是一种工具类,就像是容器,储存任意数量的具有共同属性的对象 在编程时,常常需要集中存放多 ...

  8. java 中的 viewUtils框架

    IoC的概念介绍 控制反转(IOC)模式(又称DI:Dependency Injection)就是Inversion of Control,控制反转.在Java开发中,IoC意 味着将你设计好的类交给 ...

  9. Java中的集合框架(下)

    学生选课--判断Set中课程是否存在 package com.imooc.collection; import java.util.ArrayList; import java.util.Arrays ...

  10. Java中的三大框架分别有什么用

    一.Spring Spring是一个解决了许多在J2EE开发中常见的问题的强大框架. Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯.Spring的架构基础是 ...

随机推荐

  1. HouseParty原创故事全角色关系及主线剧情介绍(最新版)

    这是原创故事的主要的角色的主线及支线剧情的介绍及攻略和注意事项等. 这里的图比哔哩哔哩上的图清楚一点,哔哩哔哩同号:宅猫君007 以上是全角色的关系图 最新版本的游戏下载就在我的网站上:https:/ ...

  2. Mybatis Plus的@TableId标签

    @TableId1.如果数据库字段设成user_id在初始生成后,在代码中会变成userId,不会设置成主键使用**@TableId(value="user_id",type = ...

  3. vue特殊attribute-ref

    vue.js中文社区文档:ref 被用来给元素或子组件注册引用信息.引用信息将会注册在父组件的 $refs 对象上.如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素:如果用在子组件上,引 ...

  4. Atm/抢掠计划——题解

    题目描述 样例 6 7 1 2 2 3 3 5 2 4 4 1 2 6 6 5 10 12 8 16 1 5 1 4 4 3 5 6 47 解析 题目明显是最长路,可以用spfa求最长路,但数据范围5 ...

  5. LLM实战:LLM微调加速神器-Unsloth + LLama3

    1. 背景 五一结束后,本qiang~又投入了LLM的技术海洋中,本期将给大家带来LLM微调神器:Unsloth. 正如Unsloth官方的对外宣贯:Easily finetune & tra ...

  6. 用pageOffice控件实现 office word文档在线编辑 表格中写数据的方法

    PageOffice对Word文档中Table的操作,包括给单元格赋值和动态添加行的效果. 1 应用场景 OA办公中,经常要在文档的指定位置表格,填充后端指定数据. 如word文档中,表格数据 如下表 ...

  7. smtplib详解,发送邮件

    创建邮箱账号 1.官网登录邮箱. 2.在邮箱的主界面找到"设置",新版的主界面与旧版稍有不同,一般位于上方,齿轮状的即是. 3.点击齿轮状的设置标志,会弹出一个下拉菜单,在最后有我 ...

  8. Istio(一):服务网格和 Istio 概述

    目录 一.模块概览 二.微服务架构 三.服务网格概述 3.1 服务网格概述 3.2 为什么需要服务网格? 四.istio简介 4.1 Istio 简介 4.2 流量管理 4.3 可观察性 4.4 安全 ...

  9. 构建自定义镜像并优化dockerfile文件

    目录 一.系统环境 二.前言 三.镜像构建步骤 四.dockerfile文件常用指令 4.1 dockerfile文件常用指令 4.2 RUN.CMD.ENTRYPOINT的区别 五.构建centos ...

  10. Vue——方法(methods)

    我们用 methods 选项向组件实例添加方法,它应该是一个包含所需方法的对象: <div id="app"></div> <script> c ...