先上结论

模运算运算慢20%到30%

这是通过实验的方式得到的结论.因为没有大大可以进行明确指导,所以我以最终运行的结果为准.欢迎指正.

测试代码

@Test
public void test10() {
int a, b, temp, count = 100000000;
long start, time; Random random = new Random(); while (true) {
System.out.println("-----------------------------------------------");
a = random.nextInt();
b = random.nextInt(); // 模运算部分
start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
temp = a % b;
preventOptimization(temp);
}
long modulo = System.currentTimeMillis() - start; // 与运算部分
start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
temp = a & b;
preventOptimization(temp);
}
long and = System.currentTimeMillis() - start; // 计算两种运算的比
BigDecimal bigDecimal = new BigDecimal(and)
.divide(new BigDecimal(modulo), 6, ROUND_DOWN);
System.out.println(String.format("modulo: %sms, and: %sms, scale: %s", modulo, and, bigDecimal));
}
} // private static int preventOptimizationVar = 0; // A /**
* 用于阻止jvm的字节码优化技术生效,优化掉for循环中的代码<br>
*
* @param num
*/
private static void preventOptimization(int num) {
// preventOptimizationVar += num; // A
}

注意事项

启动时,需要添加JVM参数-Djava.compiler=NONE阻止虚拟机的JIT优化

一些迷之调用的解释

  1. 方法preventOptimization的作用本来是为了防止for循环内的运算单元被优化.从结果看,无法抵御JIT优化,实际上只阻止了字节码优化.
  2. 同样是方法preventOptimization.内部添加了一个对成员变量preventOptimizationVar的操作,本意同样是是为了阻止JIT优化,但效果出现偏差.
  3. 最终,只能使用JVM参数-Djava.compiler=NONE阻止JIT优化,同时调用空方法preventOptimization阻止字节码优化
  4. 为了整理其中的关联,进行如下整理

针对preventOptimization方法,preventOptimizationVar操作与-Djava.compiler=NONE参数之间的交叉测试

--------------------------- -Djava.compiler=NONE 不使用-Djava.compiler=NONE
preventOptimization(空方法) 目标结果 只能执行第一次while,之后除数为0抛出异常.应该是for循环被优化掉了
preventOptimization 执行变得极慢且比值随机位于1两侧.可能是因为操作成员变量的时间已经把运算的时间稀释了 两种运算的for的平均用时只有个位数的毫秒数.一般为4ms或5ms.可以断定发生了JIT优化.但是这又与完全跳过for循环的行为不同.中间产生了数毫秒的操作时间.
不调用preventOptimization 目标结果 只能执行第一次while,之后除数为0抛出异常.应该是for循环被优化掉了

注: 上面的测试结果基于intel平台上的ubuntu18.4操作系统.后面我会补上AMD平台上的Windows系统的执行表格.它们之间会有轻微的不同

后记

  1. 针对-Djava.compiler=NONE,明确的禁用了JIT优化
  2. 针对字节码优化需要回去翻书确认实际作用与效果
  3. 这个代码在不同的物理机上出现了一些差异.家中的电脑是AMD的锐龙CPU,其结果恒定为0.73左右.而在公司的Intel CPU上运行,结果稳定在0.87左右.
  4. 目前我无法这种计算方式是否是正确的,虽然得出了模运算运算慢的结论.身边没有大大,无法对我的这种做法进行评价.也就无法确定结果的正确性.也就是说,我有可能用了错误的方式,得到这正确的答案.这种可能的本末倒置实在让人头痛.

后记的后记

对于目前的这种情况.要想完全弄清谁快谁慢,其实可以用一个最简单也最直观的方法进行确认.那就是去翻JDK源码.先在字节码里找到负责运算与运算的指令,然后去找这个指令JDK实现

更新

看了下编译后的字节码,代码中使用了如下的指令进行操作

  1. 运算使用指令irem.将操作数栈的两个值进行余运算(注意,这里用的是余运算.它不同于模运算)
  2. 运算使用指令iand.将操作数栈的两个值进行与运算

下面需要找到JDK是怎么执行字节码文件中的每个指令的.

不要和我说什么几个阶段,每个阶段都干什么.这可能是个大坑.所以我得翻书(鸽了)啊

Java中"或"运算与"与"运算快慢的三三两两的更多相关文章

  1. Java中Byte类型数据在运算中的问题

    比如: byte a=1; byte b=2; byte c; c=a+b; //这样是计算不出c,是错误的 c=a+1; //这样也是不能计算c的 c=64+1; //为什么这样就能计算c,在Jav ...

  2. 关于JAVA中Byte数据类型二进制赋值运算报错问题

    自从JDK7更新之后,新增了二进制变量的表示,支持将整数类型用二进制来表示,用0b开头: 例如: byte b= (byte) 0b1000_0001; short s = (short) 0b100 ...

  3. java中&和&&的区别 位运算

    1.1. 逻辑与的运算符功能 1.1.1. 测试&& public static void main(String[] args) { int x=5; if (x==6 && ...

  4. Java中使用md5进行hash运算

    public class Md5Util { /** * @author Bean_bag * @description 进行Hash运算 * * @param input 参数字符串 * @retu ...

  5. 042、Java中逻辑运算之短路或运算“||”

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  6. 041、Java中逻辑运算之普通或运算“|”

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  7. 040、Java中逻辑运算之短路与运算“&&”

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  8. 039、Java中逻辑运算之普通与运算“&”

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  9. Java中「与运算,或运算,异或运算,取反运算。」

    版权声明一:本文为博主原创文章,转载请附上原文出处链接和本声明.版权声明二:本网站的所有作品会及时更新,欢迎大家阅读后发表评论,以利作品的完善.版权声明三:对不遵守本声明或其他违法.恶意使用本网内容者 ...

  10. java使用DateUtils对日期进行运算

    最近在写数据上传的程序,需要对Date进行一些数学运算,个人感觉在java中,日期的数学运算还是比较常用的,所以把Date的数学运算都玩了一下.试了一下,发现DateUtils这个工具类对于Date的 ...

随机推荐

  1. 转:关于java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication的解决

    在这个控制板中,出现了这个问题 java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication 虽然明显知道是 ...

  2. node - 流 浅析

    概念 流(stream)是 Node.js 中处理流式数据的抽象接口. stream 模块用于构建实现了流接口的对象. Node.js 提供了多种流对象. 例如,HTTP 服务器的请求和 proces ...

  3. iOS导出远程推送所需要的P12 或pem文件

    http://www.saitjr.com/ios/ios-export-remote-notification-p12-pem-file.html iOS导出远程推送所需要的P12 或pem文件 h ...

  4. go-channel处理高并发请求

    目录 go-channel处理高并发请求 一.Channel简介 二.处理包并发请求 三.测试 1.测试工具 2.测试结果 go-channel处理高并发请求 最近看了一篇文章讲解怎样使用go-cha ...

  5. Mybatis_resultMap的关联方式实现多表查询(一对多)

    a)在 ClazzMapper.xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应学生的信息. b)通过<resultMap>定义映射关系, 并通过<c ...

  6. springboot自动装配(3)---条件注解@Conditional

    之前有说到springboot自动装配的时候,都是去寻找一个XXXAutoConfiguration的配置类,然而我们的springboot的spring.factories文件中有各种组件的自动装配 ...

  7. Linux(CentOS)安装SQL Server

    1.下载Microsoft SQL Server Red Hat 存储库配置文件 curl -o /etc/yum.repos.d/mssql-server.repo https://packages ...

  8. IPV6技术笔记(剖析IPv4toIPv6)

    IPV6技术笔记 IPv6地址入门概念 什么是IPv6? IPv6,全称Internet Protocol version 6,即网际协议版本6,也叫互联网通信协议第六版.是互联网工程任务组(IETF ...

  9. 面试必问:JVM类加载机制详细解析

    前言 在Java面试中,简历上有写JVM(Java虚拟机)相关的东西,JVM的类加载机制基本是面试必问的知识点. 类的加载和卸载 JVM是虚拟机的一种,它的指令集语言是字节码,字节码构成的文件是cla ...

  10. OS OSTEP (Operating Systems Three Easy pieces 操作系统导论 )

    读<OSTEP>的一点重点记录与感悟 (未完) Chapter-2 第二章 1. 操作系统的设计目标:  抽象.高性能.保护.不间断运行. 抽象:建立一些“抽象”,让操作系统方便和易于使用 ...