如何提升Java循环中代码执行性能?两类计算代码优化问询
循环内数值计算的性能优化咨询
单次执行时Code 1比Code 2快,但在5000万次循环中Code 1性能最差。现寻求以下方案:
- 是否可优化Code 1使其循环性能提升?
- 有没有更高效的方式完成循环内的这类计算?
补充:经@Sweeper确认,两类代码中Code 1实际执行速度均更慢,重点聚焦循环内计算的性能优化。
原始测试代码
int [] arr1 = new int[50000000]; for (int i = 0; i < 50000000; i++) { arr1[i] = i + 1000; } //code 1: long startTime1 = System.nanoTime(); int som1 = 426; double a1 = (double) ((((double) Math.round((double) Math.pow((double) arr1[arr1.length - 1] / (double) som1, 2)) - 1) / 50 % 1) * 50) + 1; int a2 = (int) Math.round(a1); long estimatedTime1 = System.nanoTime() - startTime1; System.out.println("Code 1: " + estimatedTime1); //code 2: long startTime2 = System.nanoTime(); int som2 = 426; double a3 = (double) arr1[arr1.length - 1] / (double) som2; double a4 = (double) (Math.round(a3 * a3) - 1); double a5 = (double) a4 / 50; double a6 = (double) Math.floor(a5); double a7 = (double) ((a5 - a6) * 50) + 1; int a8 = (int) Math.round(a7); long estimatedTime2 = System.nanoTime() - startTime2; System.out.println("Code 2: " + estimatedTime2); //code 1 inside for loop: long startTime3 = System.nanoTime(); int som3 = 426; for (int j1 = 0; j1 < arr1.length; j1++) { double a9 = (double) ((((double) Math.round((double) Math.pow((double) arr1[j1] / (double) som1, 2)) - 1) / 50 % 1) * 50) + 1; int a10 = (int) Math.round(a9); } long estimatedTime3 = System.nanoTime() - startTime3; System.out.println("Code 1 inside for loop: " + estimatedTime3); //code 2 inside for loop: long startTime4 = System.nanoTime(); int som4 = 426; for (int j2 = 0; j2 < arr1.length; j2++) { double a11 = (double) arr1[j2] / (double) som4; double a12 = (double) (Math.round(a11 * a11) - 1); double a13 = (double) a12 / 50; double a14 = (double) Math.floor(a13); double a15 = (double) ((a13 - a14) * 50) + 1; int a16 = (int) Math.round(a15); } long estimatedTime4 = System.nanoTime() - startTime4; System.out.println("Code 2 inside for loop: " + estimatedTime4);
优化方案
1. Code 1针对性优化:替换Math.pow核心瓶颈
Code 1的最大性能问题是Math.pow(x,2),这个通用幂运算函数内部逻辑复杂,远不如直接用x*x高效。循环5000万次时,这个开销会被无限放大。同时提前将常量som转为double,避免循环内重复类型转换。
修改后的Code 1循环版本:
long startTime3 = System.nanoTime(); int som3 = 426; double somDouble = 426.0; // 提前转double,减少循环内转换开销 for (int j1 = 0; j1 < arr1.length; j1++) { double x = arr1[j1] / somDouble; double squared = x * x; // 替换Math.pow(x,2) double a9 = ((Math.round(squared) - 1) / 50 % 1) * 50 + 1; int a10 = (int) Math.round(a9); } long estimatedTime3 = System.nanoTime() - startTime3; System.out.println("Optimized Code 1 inside for loop: " + estimatedTime3);
2. 通用循环计算优化技巧
- 简化数学运算逻辑:分析计算式的等价形式,减少冗余运算。比如
(a /50 %1)*50等价于a %50(正数场景下),可直接替换,省去两次浮点运算:
原计算((Math.round(squared)-1)/50 %1)*50 +1可简化为((Math.round(squared)-1) %50) +1 - 优先用整数运算替代浮点:如果业务允许,将计算逻辑转移到整数域。比如先计算
arr1[j1] * arr1[j1](用long避免溢出),再除以som*som后取整,减少浮点转换和运算开销:long somLong = 426L; long somSquared = somLong * somLong; for (int j1 = 0; j1 < arr1.length; j1++) { long numSquared = (long)arr1[j1] * arr1[j1]; long rounded = Math.round((double)numSquared / somSquared); int result = (int)((rounded -1) %50) +1; } - 并行化处理大循环:利用Java并行流或手动多线程,把5000万次循环拆分到多个CPU核心执行:
long startTimeParallel = System.nanoTime(); int som = 426; double somDouble = 426.0; Arrays.stream(arr1).parallel().forEach(num -> { double x = num / somDouble; double squared = x * x; int result = (int) Math.round(((Math.round(squared)-1) %50) +1); }); long estimatedTimeParallel = System.nanoTime() - startTimeParallel; System.out.println("Parallel optimized version: " + estimatedTimeParallel);
3. 优化验证注意事项
JVM的即时编译(JIT)会对循环做自动优化,不同JDK版本、硬件环境的测试结果可能有差异。建议多次运行取平均结果,或关闭JIT的部分优化选项,确保测试数据准确。
内容的提问来源于stack exchange,提问作者JOAO12
相关产品推荐
相关产品推荐

