Java循环效率

2024-01-12

我正在比较 Java 中嵌套的 for、while 和 do-while 循环的效率,并且遇到了一些奇怪的结果,需要帮助理解。

public class Loops {
    public static void main(String[] args) {
        int L = 100000;    // number of iterations per loop
        // for loop
        double start = System.currentTimeMillis();
        long s1 = 0;
        for (int i=0; i < L; i++) {
            for (int j = 0; j < L; j++) {
                s1 += 1;
            }
        }
        double end = System.currentTimeMillis();
        String result1 = String.format("for loop: %.5f", (end-start) / 1000);
        System.out.println(s1);
        System.out.println(result1);

        // do-while loop
        double start1 = System.currentTimeMillis();
        int i = 0;
        long s2 = 0;
        do {
            i++;
            int j = 0;
            do {
                s2 += 1;
                j++;
            } while (j < L);
        } while (i < L);
        double end1 = System.currentTimeMillis();
        String result2 = String.format("do-while: %.5f", (end1-start1) / 1000);
        System.out.println(s2);
        System.out.println(result2);

        // while loop
        double start2 = System.currentTimeMillis();
        i = 0;
        long s3 = 0;
        while (i < L) {
            i++;
            int j = 0;
            while (j < L) {
                s3 += 1;
                j++;
            }
        }
        double end2 = System.currentTimeMillis();
        String result3 = String.format("while: %.5f", (end2-start2) / 1000);
        System.out.println(s3);
        System.out.println(result3);
    }
}

所有循环各自的计数器总和为 100 亿;结果让我困惑:

for 循环:6.48300

做同时:0.41200

同时:9.71500

为什么 do-while 循环如此快?这种性能差距与 L 的任何更改并行扩展。我独立运行这些循环,它们执行相同的操作。


我已经运行了您提供的代码,并且也惊讶地发现这些性能差异。在好奇心的引导下,我开始调查并发现,尽管这些循环似乎在做同样的事情,但它们之间存在一些重要的区别。

第一次运行这些循环后我的结果是:

for loop: 1.43100
do-while: 0.51300
while: 1.54500

但是当我运行这三个循环至少 10 次时,每个循环的性能几乎相同。

for loop: 0.43200
do-while: 0.46100
while: 0.42900

JIT 能够随着时间的推移优化这些循环,但一定存在一些差异,导致这些循环具有不同的初始性能。事实上,实际上有两个区别:

  • The do-while循环进行的比较次数少于for and while loops

为简单起见,假设 L = 1

long s1 = 0;
for (int i=0; i < L; i++) {
    for (int j = 0; j < L; j++) {
        s1 += 1;

外循环:0 内循环:0 内循环:1 外循环:1

共4次比较

int i = 0;
long s2 = 0;
do {
    i++;
    int j = 0;
    do {
        s2 += 1;
        j++;
    } while (j < L);
} while (i < L);

内循环:1 外循环:1

共2次比较

  • 生成的字节码不同

为了进一步调查的目的,我对你的课程做了一些轻微的改变,但不影响它的工作方式。

public class Loops {
    final static int L = 100000; // number of iterations per loop

    public static void main(String[] args) {
        int round = 10;
        while (round-- > 0) {
            forLoop();
            doWhileLoop();
            whileLoop();
        }
    }

    private static long whileLoop() {
        int i = 0;
        long s3 = 0;
        while (i++ < L) {
            int j = 0;
            while (j++ < L) {
                s3 += 1;
            }
        }
        return s3;
    }

    private static long doWhileLoop() {
        int i = 0;
        long s2 = 0;
        do {
            int j = 0;
            do {
                s2 += 1;
            } while (++j < L);
        } while (++i < L);
        return s2;
    }

    private static long forLoop() {
        long s1 = 0;
        for (int i = 0; i < L; i++) {
            for (int j = 0; j < L; j++) {
                s1 += 1;
            }
        }
        return s1;
    }
}

然后编译并调用javap -c -s -private -l Loop获取字节码。

首先是doWhileLoop的字节码。

   0:   iconst_0        // push the int value 0 onto the stack
   1:   istore_1        // store int value into variable 1 (i)
   2:   lconst_0        // push the long 0 onto the stack
   3:   lstore_2        // store a long value in a local variable 2 (s2)
   4:   iconst_0        // push the int value 0 onto the stack
   5:   istore  4   // store int value into variable 4 (j)
   7:   lload_2     // load a long value from a local variable 2 (i)
   8:   lconst_1        // push the long 1 onto the stack
   9:   ladd        // add two longs
   10:  lstore_2        // store a long value in a local variable 2 (i)
   11:  iinc    4, 1    // increment local variable 4 (j) by signed byte 1
   14:  iload   4   // load an int value from a local variable 4 (j)
   16:  iload_0     // load an int value from a local variable 0 (L)
   17:  if_icmplt   7   // if value1 is less than value2, branch to instruction at 7
   20:  iinc    1, 1    // increment local variable 1 (i) by signed byte 1
   23:  iload_1     // load an int value from a local variable 1 (i)
   24:  iload_0     // load an int value from a local variable 0 (L)
   25:  if_icmplt   4   // if value1 is less than value2, branch to instruction at 4
   28:  lload_2     // load a long value from a local variable 2 (s2)
   29:  lreturn     // return a long value

现在是 while Loop 的字节码:

   0:   iconst_0        // push int value 0 onto the stack
   1:   istore_1        // store int value into variable 1 (i)
   2:   lconst_0        // push the long 0 onto the stack
   3:   lstore_2        // store a long value in a local variable 2 (s3)
   4:   goto        26
   7:   iconst_0        // push the int value 0 onto the stack
   8:   istore  4   // store int value into variable 4 (j)
   10:  goto        17
   13:  lload_2     // load a long value from a local variable 2 (s3)
   14:  lconst_1        // push the long 1 onto the stack
   15:  ladd        // add two longs
   16:  lstore_2        // store a long value in a local variable 2 (s3)
   17:  iload   4   // load an int value from a local variable 4 (j)
   19:  iinc    4, 1    // increment local variable 4 (j) by signed byte 1
   22:  iload_0     // load an int value from a local variable 0 (L)
   23:  if_icmplt   13  // if value1 is less than value2, branch to instruction at 13
   26:  iload_1     // load an int value from a local variable 1 (i)
   27:  iinc    1, 1    // increment local variable 1 by signed byte 1
   30:  iload_0     // load an int value from a local variable 0 (L)
   31:  if_icmplt   7   // if value1 is less than value2, branch to instruction at 7
   34:  lload_2     // load a long value from a local variable 2 (s3)
   35:  lreturn     // return a long value

为了使输出更具可读性,我附加了注释,描述了每条指令的作用Java字节码指令列表 http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings.

如果您仔细观察,您会发现这两个字节码之间存在重要差异。 while 循环(for 循环也是如此)有 if 语句 (if_icmplt指令)在字节码末尾定义。这意味着要检查第一个循环的退出条件,必须调用第 26 行的 goto,并且类似地,必须调用第二个循环的第 17 行的 goto。

上述字节码是在 Mac OS X 上使用 javac 1.6.0_45 生成的。

Summary

我认为不同数量的比较加上 while 和 for 循环字节码中 goto 指令的存在是这些循环之间性能差异的原因。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java循环效率 的相关文章

  • 连接外部 Accumulo 实例和 java

    我正在尝试使用 Accumulo 连接到虚拟机 问题是 我无法将其连接到 Java 中 我可以看到 Apache 抛出的网页 但我无法让它与代码一起工作 我认为这是缺乏知识的问题而不是真正的问题 但我找不到这方面的文档 所有示例都使用 lo
  • 如何以编程方式使用包含多列的 where-in 子句执行 PostgreSQL 查询?

    我的查询是这样的 select from plat customs complex where code t code s in 01013090 10 01029010 90 它在 psql 控制台中运行良好 我的问题是如何在客户端代码中
  • Java 中的 <-- 是什么? [复制]

    这个问题在这里已经有答案了 我遇到了下面的片段 它输出到4 3 2 1 我从来没有遇到过 lt 在爪哇 Is lt 使 var1 的值变为 var2 的运算符 public class Test public static void mai
  • 为什么在 10 个 Java 线程中递增一个数字不会得到 10 的值?

    我不明白 a 的值为0 为什么 a 不是10 那段代码的运行过程是怎样的 是否需要从Java内存模型来分析 这是我的测试代码 package com study concurrent demo import lombok extern sl
  • 以相反的顺序打印任何集合中的项目?

    我在 使用 Java 进行数据结构和问题解决 一书中遇到以下问题 编写一个例程 使用 Collections API 以相反的顺序打印任何 Collection 中的项目 不要使用 ListIterator 我不会把它放在这里 因为我想让有
  • 有人用过 ServiceLoader 和 Guice 一起使用吗?

    我一直想通过我们的应用程序 构建系统进行更大规模的尝试 但更高的优先级不断将其推到次要地位 这似乎是加载 Guice 模块的好方法 并且避免了关于 硬编码配置 的常见抱怨 单个配置属性很少会自行更改 但您几乎总是会有一组配置文件 通常用于不
  • 时间复杂度和运行时间有什么区别?

    时间复杂度和运行时间有什么区别 它们是一样的吗 运行时间是指程序运行所需的时间 时间复杂度是对输入大小趋于无穷大时运行时间渐进行为的描述 您可以说运行时间 是 O n 2 或其他什么 因为这是描述复杂性类和大 O 表示法的惯用方式 事实上
  • 为什么用scala写的代码比用java写的慢6倍?

    我不确定我在编写 scala 代码时是否犯了一些错误 问题是 The four adjacent digits in the 1000 digit number that have the greatest product are 9 9
  • 在 Spring 中为 @Pathvariable 添加类级别验证

    在发布这个问题之前 我已经做了很多研究并尝试了很多可用的解决方案 这是我陷入的棘手情况 我有一个 Spring 控制器 它有多个请求映射 它们都有 PathVariables 控制器如下所示 Controller EnableWebMvc
  • Android 认为我没有关闭数据库!为什么?

    我有一个 SQLiteDatabase 数据成员 我在 onCreate 中初始化它 并在 onPause onStop 和 onDestroy 中调用 close 它在 onResume 中重新初始化 它似乎运行得很好 但当我查看调试器时
  • 通过增加索引之和来生成排序组合的有效方法

    对于启发式算法 我需要一个接一个地评估特定集合的组合 直到达到停止标准 由于它们很多 目前我正在使用以下内存高效迭代器块生成它们 受到 python 的启发 itertools combinations http docs python o
  • UseCompressedOops JVM 标志有什么作用以及何时应该使用它?

    HotSpot JVM 标志是什么 XX UseCompressedOops我应该做什么以及什么时候使用它 在 64 位 Java 实例上使用它 与不使用它 时 我会看到什么样的性能和内存使用差异 去年大多数 HotSpot JVM 都默认
  • Joshua Bloch 的构建器设计模式有何改进?

    早在 2007 年 我就读过一篇关于 Joshua Blochs 所采用的 构建器模式 的文章 以及如何修改它以改善构造函数和 setter 的过度使用 特别是当对象具有大量属性 其中大部分属性是可选的 时 本文对此设计模式进行了简要总结
  • 如何向页面添加 HTML 页眉和页脚?

    如何使用 itext 从 html 源添加标题到 pdf 目前 我们已经扩展了 PdfPageEventHelper 并重写了这些方法 工作正常 但当我到达 2 个以上页面时 它会抛出 RuntimeWorkerException Over
  • Tomcat 6 未从 WEB-INF/lib 加载 jar

    我正在尝试找出我的 tomcat 环境中的配置问题 我们的生产服务器正在运行 tomcat 安装并从共享 NFS 挂载读取战争 然而 当我尝试使用独立的盒子 及其配置 进行同样的战争时 我收到下面发布的错误 有趣的是 如果我将 WEB IN
  • Lombok 不适用于 Eclipse Neon

    我下载了lombok jar lombok 1 16 14 jar 并将其放入我的下载中 然后我点击这个 jar 执行正确地识别了我的 MacOS 上的 Eclipse 实例 然后我选择了我想要的实例 Lombok也在pom xml中指定
  • 我所有的 java 应用程序现在都会抛出 java.awt.headlessException

    所以几天前我有几个工作Java应用程序使用Swing图书馆 JFrame尤其 他们都工作得很好 现在他们都抛出了这个异常 java awt headlessexception 我不知道是什么改变了也许我的Java版本不小心更新了 谢谢你尽你
  • 使用 DBCP 配置 Tomcat

    在闲置一段时间 几个小时 后 我们收到了 CommunicationsException 来自 DBCP 错误消息 在异常中 位于这个问题的末尾 但我没有看到任何配置文件中定义的 wait timeout 我们应该看哪里 在 tomcat
  • 在会话即将到期之前调用方法

    我的网络应用程序有登录的用户 有一个超时 在会话过期之前 我想执行一个方法来清理一些锁 我已经实现了sessionListener但一旦我到达public void sessionDestroyed HttpSessionEvent eve
  • 关闭扫描仪是否会影响性能

    我正在解决一个竞争问题 在问题中 我正在使用扫描仪获取用户输入 这是 2 个代码段 一个关闭扫描器 一个不关闭扫描器 关闭扫描仪 import java util Scanner public class JImSelection publ

随机推荐

  • Spring Integration - 当服务激活器组件中发生异常时写入错误队列

    我开始使用 Spring 集成 如果可能的话 我不知道如何解决这种情况 我想自动 捕获 应用程序的服务激活器中可能发生的每个异常 并将此错误发送到专用队列 网关不是一个解决方案 因为我需要一些自定义代码 所以如果我正确理解了原理 我必须使用
  • 使图像文件在 Lollipop 上的 Android Gallery 中可见

    我试图使应用程序中拍摄的一些照片在图库中可见 以便可以在应用程序外部共享和查看它们 但我想将图像本身保留在应用程序的数据目录中 以便当应用程序被删除 它们被删除 因此它们存储在 sdcard Android data appID 图片 子文
  • Flutter 嵌套 JSON 解析

    我这里有一个嵌套的 JSON api Employee Name Michael Jackson Identification 881228145031 Company Test Corporate DateOfBirth 1988 12
  • Gettext 不起作用,没有错误消息,使用 php 5.3

    我已经在这件事上摸索了好几天了 但没有成功 我只是想让 gettext 工作 发生的情况是打印 php 文件中写入的字符串 而不是翻译后的字符串 IE 如果我做 echo gettext Service 然后打印 Service 而不是瑞典
  • Visual Studio 2008 中缺少 T4 代码生成?

    所以我决定卷起袖子尝试一下 VS2008 内置的 T4 代码生成 我打算继续写这篇文章 http www olegsych com 2008 09 t4 tutorial creatating your first code generat
  • Prolog - 描述事实和规则

    我想在序言中描述以下事实和规则 Nick 正在使用 Java 进行编程 Nick 正在使用 Python 编程 Nick 是任何使用 Java 和 Python 编程的人的朋友 Jim 可以使用 Nick 所使用的所有语言进行编程 我找到了
  • 如果不可能,计算 x^n 并返回整数限制而不溢出的元函数?

    考虑以下代码 template
  • 如何将 ft_min_word_len=4 修改为 ft_min_word_len=1 以便 osclass 3.7.1 可以搜索最少 1 个字符的单词,而不是 4?

    我想将搜索的最小字符长度从 4 更改为 1 我找到了这个文档https doc osclass org Fine Tuning MySQL Full Text Search Improving search https doc osclas
  • iOS8 中的 dismissViewControllerAnimated 崩溃

    我有一个在 iOS7 0 7 1 中运行良好的应用程序 自从上次 iOS 更新 8 0 以来 dismissViewControllerAnimated 每次都会崩溃 有人看到同样的事情吗 我有一个控件可以调用第二个控制器 detailVi
  • 您可以运行可从公共IP访问的/host firebase模拟器吗?

    我正在使用 firebase 模拟器在我的计算机上托管一些 GCF 功能 它们被配置为在 localhost 5001 上运行 托管 这很好用 我现在在我的应用程序中使用 Google Tasks 并且我的任务需要调用 GCF 函数 任务不
  • 在 jython 中实例化 webclient 对象给出奇怪的结果

    我正在尝试在 jython 脚本中使用 java 的 WebClient jar 我正在运行 jython 脚本 如下所示 jython Dpython path home tipu Dropbox dev proj lib test py
  • MPAndroidChart:“图例”现在已弃用 getColors()。我应该用什么来代替?

    我正在 MPAndroidChart 中显示 PieChart 的自定义图例 但是 getColors 和 getLabels 现已弃用 我一直在使用它们分别获取 int 数组和字符串数组 但我似乎找不到直接的替代方案 我错过了一些明显的东
  • 还记得在 parse.com android 上的用户登录吗?

    您好 我特别尝试使用解析 api 进行登录 但我无法获取代码来检查用户之前是否已登录 我在解析网站上发布了这个问题 但没有答案 我在教程中找到了这段代码 但不确定将其放置在我的启动器活动中的何处 Intent intent if Parse
  • 如何使用 PowerShell 将 Api 权限添加到 Azure 应用程序注册

    我正在找出 Azure PowerShell 中的命令来添加User ReadApe 在 Azure 中注册我的应用程序的权限 我可以找到一些使用的例子 Azure 但更喜欢使用 Az命令 例如https learn microsoft c
  • 如何检查我的应用程序中的 SDK 是否正在收集任何广告 ID

    Google 向我发送了一条警告 通知我我的一个应用程序正在收集信息安卓设备 ID and 广告ID信息 有没有什么工具可以用来测试这个活动涉及哪个SDK P s 我正在使用以下 SDK Admob 中介 Firebase Onesigna
  • 如何暂时禁用EGit?

    当做类似的事情时git repack从命令行 包被锁定并且无法删除 从而使存储库大小加倍 罪魁祸首很可能是 EGit 保持文件打开 这在 Windows 中是不好的 退出 Eclipse 是我所知道的唯一解决方法 我发现了本文 https
  • AWS Glue 截断 Redshift 表

    我创建了一个 Glue 作业 将数据从 S3 csv 文件 复制到 Redshift 它可以工作并填充所需的表 但是 我需要在此过程中清除表 因为在该过程完成后我留下了重复的记录 我正在寻找一种方法将这种清除添加到胶水过程中 任何意见 将不
  • 从 Android 应用程序分享视频

    我们是一个视频托管门户 用户可以根据观看次数上传视频并从中获利 我们最近推出了一款 Android 应用程序 并尝试将 分享 按钮集成到每个视频中 这是我们放置的代码 Intent intent new Intent try URL url
  • 接口和标头

    今天我遇到了 C 接口的概念 我有一个希望很简单的问题来看看我是否理解它们 它们与 C 头文件非常相似吗 我的意思是 根据我得到的信息 您定义了类的主干 但没有实际定义它的功能 这有点类似于标头 对吗 我阅读了整个 MSDN 定义 但它并没
  • Java循环效率

    我正在比较 Java 中嵌套的 for while 和 do while 循环的效率 并且遇到了一些奇怪的结果 需要帮助理解 public class Loops public static void main String args in