2021-07-17 Java代码的自动优化

代码案例

一、原始代码

public class Test {
    public static void main(String[] args) {
        long then = System.currentTimeMillis();
        double result;
        for (int i = 0; i < 1000000000; i++) {
            result = i*i;
        }
        long now = System.currentTimeMillis();
        System.out.println(now - then);
    }
}

上面代码执行耗时4ms。原因是 result 没有被使用到,智能的编译器就会对代码进行优化,所以 jvm 最终执行的是以下代码:

public class Test {
    public static void main(String[] args) {
        long then = System.currentTimeMillis();
        long now = System.currentTimeMillis();
        System.out.println(now - then);
    }
}

二、将结果定义为成员变量

我们将 result 定义为成员变量后,执行用时为175ms。如果JVM 将 result 存放到某个寄存器中,并且被写了多次,但是没有读取操作(因为其他线程不能读取这个寄存器),因此,除了最终结果可以优化掉所有的循环结果。

public class Test {
    static double result;
    public static void main(String[] args) {
        long then = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            result = i*i;
        }
        long now = System.currentTimeMillis();
        System.out.println(now - then);
    }
}

三、将结果使用 volatile 修饰

将 result 使用volatile修饰后,再次执行用时 1873ms。由于 result 用 volatile 定义,确保 JVM 必须保存每次循环的计算结果,JVM 不能优化掉这些计算,因为它无法知道是否会有其他线程过来,从主存(main memory)中读取这个值。

public class Test {
    volatile static double result;
    public static void main(String[] args) {
        long then = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            result = i*i;
        }
        long now = System.currentTimeMillis();
        System.out.println(now - then);
    }
}

验证

在《java性能权威指南》中写道,这些是由于java的编译器优化导致的。我们可以查看下原始代码的字节码。从反编译的字节码来看,编译器并没有进行优化掉没用到的循环代码,这个还需进一步验证原因。

Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1
       4: iconst_0
       5: istore        5
       7: iload         5
       9: ldc           #3                  // int 1000000000
      11: if_icmpge     27
      14: iload         5
      16: iload         5
      18: imul
      19: i2d
      20: dstore_3
      21: iinc          5, 1
      24: goto          7
      27: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      30: lstore        5
      32: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      35: lload         5
      37: lload_1
      38: lsub
      39: invokevirtual #5                  // Method java/io/PrintStream.println:(J)V
      42: return
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值