橘子学JDK之JMH-03(@State)

这里我们来搞官方的第三个案例,引入新的注解@State。

一、案例三代码

package com.levi;/*** @Description:* @Author: Levi* @Date: 2024/4/8 18:44*/import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;// 预热注解,修改为只预热一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Warmup(iterations = 1,time = 1)
// 测试执行注解,修改为只执行一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Measurement(iterations = 1,time = 1)
public class JMHSample_03_01_States {/** Most of the time, you need to maintain some state while the benchmark is* running. Since JMH is heavily used to build concurrent benchmarks, we* opted for an explicit notion of state-bearing objects.* 在 JMH(Java 微基准测试工具)中,执行基准测试过程中需要维护状态是很重要的,特别是对于并发基准测试。* JMH 提供了显式的状态对象概念来处理这一点。** Below are two state objects. Their class names are not essential, it* matters they are marked with @State. These objects will be instantiated* on demand, and reused during the entire benchmark trial.* 在您提供的代码片段中,有两个使用 @State 注解标记的状态对象。具体的类名并不重要,但 @State 注解是关键。* 这些对象将根据需要进行实例化,并在整个基准测试试验过程中重复使用。基准测试可以访问@State标注类的声明的变量** The important property is that state is always instantiated by one of* those benchmark threads which will then have the access to that state.* That means you can initialize the fields as if you do that in worker* threads (ThreadLocals are yours, etc).* 关键点是每个状态对象都是由其中一个基准测试线程实例化的。这确保了每个基准测试线程都可以访问自己的状态对象实例。* 因此,您可以像在工作线程中那样初始化状态对象的字段。这意味着您可以在状态对象中使用 ThreadLocal 或任何其他线程特定的构造。* 就是本地变量,线程安全。*/@State(Scope.Benchmark)public static class BenchmarkState {volatile double x = Math.PI;}@State(Scope.Thread)public static class ThreadState {volatile double x = Math.PI;}/** Benchmark methods can reference the states, and JMH will inject the* appropriate states while calling these methods. You can have no states at* all, or have only one state, or have multiple states referenced. This* makes building multi-threaded benchmark a breeze.* 基准方法可以引用这些状态,并且在调用这些方法时,JMH将注入适当的状态。您可以完全没有状态,或者只有一个状态,或者引用多个状态。* 这使得构建多线程基准测试变得非常简单。** For this exercise, we have two methods.* 对于这个练习,我们有两个方法。*/@Benchmarkpublic void measureUnshared(ThreadState state) {// All benchmark threads will call in this method.// 所有的测试线程都会调用这个方法// However, since ThreadState is the Scope.Thread, each thread,will have it's own copy of the state,// and this benchmark will measure unshared case.// 然而,由于ThreadState的作用域是Scope.Thread,每个线程将拥有自己的状态副本,因此这个基准将测量不共享状态的情况。// 也就是各自操作的对象是复制了一份,不是操作的共享变量,也就是线程安全。Scope.Thread作用域是在线程本地。// 换言之就是四个线程每个线程来调用的时候,都会自己创建一个ThreadState,不共享state.x++;}@Benchmarkpublic void measureShared(BenchmarkState state) {// All benchmark threads will call in this method.//所有基准线程都将调用此方法。// Since BenchmarkState is the Scope.Benchmark, all threads will share the state instance,// and we will end up measuring shared case.// 由于BenchmarkState的作用域是Scope.Benchmark,所有线程将共享状态实例,并且我们最终将测量共享情况。// 也就是测试启动的多个线程,是操作这个共享变量的Scope.Benchmark这个作用域是再所有的Benchmark方法的state.x++;}/** You are expected to see the drastic difference in shared and unshared cases,* because you either contend for single memory location, or not. This effect* is more articulated on large machines.* 预计会看到共享和非共享情况之间的显著差异,因为您要么竞争共享内存位置,也就是共享的时候存在并发竞争,不共享的不存在。* 这种效应在大型机器上更为显著。*/public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder().include(JMHSample_03_01_States.class.getSimpleName()).threads(4) // 启动四个线程进行基准测试.forks(1).build();new Runner(opt).run();}}

二、@State

我们依然先不急着跑程序,我们看下这个代码。

@State(Scope.Benchmark)
public static class BenchmarkState {volatile double x = Math.PI;
}@State(Scope.Thread)
public static class ThreadState {volatile double x = Math.PI;
}

这里声明了两个类,一个是BenchmarkState ,他的注解是@State(Scope.Benchmark),他的作用范围是所有的Benchmark方法。
另一个是ThreadState ,他的注解是@State(Scope.Thread),他的作用范围是每个线程自己的。
然后呢,我们的两个基准测试方法。

@Benchmark
public void measureUnshared(ThreadState state)
这个方法的参数是哪个线程独享范围的state类。@Benchmark
public void measureShared(BenchmarkState state)
这个方法的参数是哪个所有Benchmark都共享的state类。

然后呢,我们会启动多个线程来启动基准测试,每个线程都会去调用这两个@Benchmark方法,不是一部分调一个,另一部分调另一个,是都会来调用。
只是调用的时候,Scope.Thread的那个类和他的变量会在每个线程都自己创建一个,他是不线程共享的。
而Scope.Benchmark这个类和他的变量是全局就一个,每个线程操作的是同一个。
所以就会产生一个结果就是:
@State(Scope.Benchmark)
public static class BenchmarkState {
volatile double x = Math.PI;
}这个方法其实是多线程竞争操作一个对象BenchmarkState的变量x,会产生并发竞争。

@State(Scope.Thread)
public static class ThreadState {
volatile double x = Math.PI;
}这个是多个线程操作的都是自己本地创建的。他们不存在并发竞争。

而且你会注意,他的每个变量x,都是加着volatile 的,他还要保证可见性在共享并发操作的时候。
现在你差不多明白了吧,这是个分别测试并发修改共享变量和每个线程各自改自己的本地变量的case。
那么不出意外的话,并发修改那指定效率不如那个共享的,因为有线程的切换,可见性的保证等等,cpu的竞争。

三、测试结果

在这里插入图片描述

四、@DefaultState

这个例子其实是官方文档的第四个例子,我们拿到这里,其实和上面那个一样的。只是这种把状态变量声明到自己本身里面了,没单独搞新的类。

package com.levi;/*** @Description:* @Author: Levi* @Date: 2024/4/8 19:23*/import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;/** Fortunately, in many cases you just need a single state object.* In that case, we can mark the benchmark instance itself to be* the @State. Then, we can reference its own fields as any* Java program does.* 幸运的是,在许多情况下,您只需要一个单独的状态对象。在这种情况下,我们可以将基准测试实例本身标记为 @State。* 然后,我们可以像任何 Java 程序那样引用它自己的字段。其实就是把原来单独声明变量的类,现在是放在自己本身里面当成一个变量。这里也可以搞多个,你可以再写个y,不是只能写一个x。* */@State(Scope.Thread)// 这里也可以标记,表示这个状态值是线程独享,也就是每个线程都创建
public class JMHSample_04_01_DefaultState {double x = Math.PI;/**这里就等价于下面,只是没有这个语法而已。@Benchmarkpublic void measure(JMHSample_04_01_DefaultState state) {state.x++;}*/@Benchmarkpublic void measure() {x++;}public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder().include(JMHSample_04_01_DefaultState.class.getSimpleName()).forks(1).build();new Runner(opt).run();}}

五、总结

没总结的,注释非常明确了。

六、参考链接

1、JMH官方文档
2、JMH官方文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/800624.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【YOLOV8】项目目录重点部分介绍和性能评估指标

目录 一 项目目录重点部分介绍 二 性能评估指标 一 项目目录重点部分介绍 1 ultralytics

揭秘Dropbear SSH:轻量级的安全外壳协议实现

在远程管理和通讯的世界里,安全是至关重要的一环。SSH(Secure Shell)协议是互联网上用于安全远程登录和其他网络服务的标准方式。当我们提到SSH时,OpenSSH可能是最广为人知的实现。然而,在资源受限的环境中&#xff0c…

windows环境变量滥用维权/提权

0x01 前提 通过滥用系统的路径搜索机制来欺骗高权限用户执行看似合法的系统二进制文件,实际上是恶意的代码或程序,从而导致升权限并执行恶意操作。 攻击的关键前提: 路径搜索顺序: 当用户在命令行或程序中执行一个命令时&#x…

kafka 高吞吐设计分析

说明 本文基于 kafka 2.7 编写。author blog.jellyfishmix.com / JellyfishMIX - githubLICENSE GPL-2.0 概括 支撑 kafka 高吞吐的设计主要有以下几个方面: 网络 nio 主从 reactor 设计模式 顺序写。 零拷贝。 producer producer 开启压缩后是批量压缩,bro…

【Qt】:常用控件(七:输入类控件)

常用控件 一.Combo Box(下拉框)二.Spin Box(微调框)三.ate Edit&Time Edit(日期微调框)四.Dial(旋钮)五.Slider(滑动条) 一.Combo Box(下拉框…

738.单调递增的数字

// 定义一个名为Solution的类 class Solution { public:// 定义公共成员函数:计算并返回大于等于输入整数N且其各位数字非降序排列的最小整数int monotoneIncreasingDigits(int N) {// 将整数N转换成字符串形式,方便操作每一位数字string strNum to_str…

23linux 自定义shell文件系统

打印环境变量,把当前子进程所有环境变量打印出来 环境变量也是一张表(指针数组以null结尾,最后条件不满足就退出了 ) 用子进程调用 结论1 当我们进行程序替换的时候 ,子进程对应的环境变量(子进程的环境变…

聚焦ChatGPT:学术写作全攻略

ChatGPT无限次数:点击直达 聚焦ChatGPT:学术写作全攻略 引言 在当今信息爆炸的时代,学术写作对于研究人员和学生来说是至关重要的技能。而随着人工智能的不断发展,ChatGPT作为一个强大的自然语言处理工具,为学术写作带来了全新的…

Mybatis执行器(Executor)

Executor简介 Executor Executor是MyBatis的核心接口之一,其中定义了数据库操作的基本方法。在实际应用中经常涉及的SqlSession接口的功能,都是基于Executor接口实现的。 BaseExecutor BaseExecutor是一个实现了Executor接口的抽象类,它实现了Execut…

pytorch 与 python版本对应关系

pytorch 与 python版本对应关系 torchtorchvisionPythonmain / nightlymain / nightly>3.8, <3.112.20.17>3.8, <3.112.10.16>3.8, <3.112.00.15>3.8, <3.111.130.14>3.7.2, <3.101.120.13>3.7, <3.101.110.12>3.7, <3.101.100.11&…

word文档拆分

Word如何拆分文档&#xff1f;-Word将文档拆分的方法 - 极光下载站 (xz7.com) 可以参考这篇&#xff0c;注意需要全部选中后再创建。 最需要注意的是&#xff0c;拆分后原文档不存在了&#xff0c;最多可以显示引用的拆分的文档&#xff0c;如果拆分有误&#xff0c;则无法恢复…

Yolov8-pose关键点检测:特征融合 | CAMixing:卷积-注意融合模块和多尺度提取能力 | 2024年4月最新成果

💡💡💡本文独家改进:CAMixingBlock更好的提取全局上下文信息和局部特征,包括两个部分:卷积-注意融合模块和多尺度前馈网络; 💡💡💡如何跟YOLOv8结合:1)放在backbone后增强对全局和局部特征的提取能力;2)放在detect前面,增强detect提取能力; 提供多种改进方…

RabbitMQ3.13.x之十一_RabbitMQ中修改用户密码及角色tgs

RabbitMQ3.13.x之十一_RabbitMQ中修改用户密码及角色tgs 文章目录 RabbitMQ3.13.x之十一_RabbitMQ中修改用户密码及角色tgs1. 修改用户的密码1. 修改密码语法2. 修改案例 2.修改角色tags1. 修改标签(tags)语法2. 修改案例 可以使用 RabbitMQ 的命令行工具 rabbitmqctl 来修改用…

【MATLAB源码-第180期】基于matlab的PTS,SLM,CPFilter三种降低OFDM系统的PAPR仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1. 限幅和滤波&#xff08;Clipping and Filtering&#xff09; 原理简介 限幅和滤波是一种基础且直观的方法&#xff0c;用于降低OFDM信号的PAPR。在限幅阶段&#xff0c;信号的幅度在达到设定阈值时会被削减&#xff0c;…

皮具5G智能制造工厂数字孪生可视化平台,推进企业数字化转型

皮具5G智能制造工厂数字孪生可视化平台&#xff0c;推进企业数字化转型。随着信息技术的快速发展&#xff0c;数字化转型已成为企业提升竞争力、实现可持续发展的关键路径。皮具行业&#xff0c;作为一个传统的手工制造业&#xff0c;正面临着巨大的市场变革和技术挑战。如何在…

红队打靶:holynix打靶流程-文件包含-文件上传-修改伪设备提权(vulnhub)

目录 开头 1.主机发现和端口扫描 2.80端口-万能密码-文件泄露 sql注入万能密码 文件泄露-读取/etc/passwd文件 sqlmap POST注入| SQL注入实现越权 | 水平越权 最后构造的sql语句,为什么这么构造嘞&#xff1f; 3.文件上传、文件解析漏洞利用 浏览器怎么访问家目录啊&…

你不知道的10个光伏冷知识!

对于光伏发电许多人都不是很了解&#xff0c;今天小编整理了10个光伏方面的冷知识分享。 1.光伏是如何诞生的&#xff1f; 1839年&#xff0c;19岁的法国贝克勒尔做物理实验时&#xff0c;发现在导电液中的两种金属电极用光照射时电流会加强&#xff0c;从而发现了“光生伏打…

C语言指针—指针和指针类型

指针是什么&#xff1f; 指针是什么&#xff1f; 指针理解的2个要点&#xff1a; 指针是内存中一个最小单元的编号&#xff0c;也就是地址 平时口语中说的指针&#xff0c;通常指的是指针变量&#xff0c;是用来存放内存地址的变量 总结&#xff1a;指针就是地址&#xff0c;口…

Flutter 单例模式的多种实现方法与使用场景分析

单例模式是一种常用的设计模式&#xff0c;用于确保一个类只有一个实例&#xff0c;并提供一个全局访问点。在Flutter应用程序中&#xff0c;单例模式可以有效地管理全局状态、资源共享和对象的生命周期。本文将介绍Flutter中实现单例模式的多种方法&#xff0c;并分析它们的使…