java中final修饰基本变量后的效率问题

今天无聊想看下我电脑一秒钟能从0加到多少,就写了这个东西

public class TestMultiThread {
    static volatile long index = 0;
    static boolean flag = true;
    public static void main(String[] args){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    Thread.sleep(1000);
                    System.out.println(index);
                    Thread.sleep(1000);
                    System.out.println(index);
                    Thread.sleep(1000);
                    System.out.println(index);
                    System.exit(0);
                }catch (Exception i){
                    i.printStackTrace();
                }
            }
        }).start();
        execute();
    }
    public static void execute(){
        while (true){
            index++;
        }
    }
}```
输出:
181768468
363750863
546204407;
后来一想,这个flag变量可以写成final,都说基本类型变量写成static final类型的会提高效率(编译阶段就确定值),于是输出结果变成了。。。
132285800
264612735
396760510
what the f...
直接将while循环条件写成“true”也是一样的输出。
我知道一定是在运行时有一些我不知道的细节导致了这个现象,大家说说自己的看法?
阅读 7.4k
5 个回答

当使用static的时候,线程执行的时候会在线程栈里为其添加一个copy,以后引用的就是线程栈内的变量。使用final或直接使用true,感觉是一回事,这个变量就不是变量了,而是一个固定的值,boolean就两个值,在虚拟机启动的时候就确定了,存储位置应该也是在一个固定的区域(perm)了。因为访问栈内数据的速度要快于访问那个‘固定区域’的速度,所以就出现了你得到的结果啦。

还有,final对性能的提升主要是针对方法来说的,它能使得在编译的时候就确定哪个方法会被访问而不是动态绑定。所谓的性能提升就表现在这里,提升的有限。举个例子:

public class Maxes {

    static volatile long index = 0;
    public static void main(String[] args) throws InterruptedException{
    final Person ps = new Student();
    new Thread(){
        public void run() {
        while(true){
            ps.say();
        }
        };
    }.start();
    Thread.sleep(1000);
    System.out.println(index);
    Thread.sleep(1000);
    System.out.println(index);
    Thread.sleep(1000);
    System.out.println(index);
    System.exit(0);
    }
}
class Person{
    public void say(){
    Maxes.index ++;
    }
}
class Student extends Person{
    public final void say(){
    Maxes.index ++;
    }
}
//120076985
//169933373  final时候的表现

谢邀。
不过我实在是没有看明白,楼主想要表达什么。
final修饰符跟效率有关系?这个我不太清楚,从来没有考虑过这个问题呢。
execute() 在你在电脑中i一秒钟能增加到多少我不太清楚,不过看你的逻辑,cpu是要爆炸的吧。
最后我们一般做性能测试,都是根据结果消耗时间换算得来。要知道你这里启动一个线程中间还有sleep唤醒线程,这都需要花时间,计算机运行速度是很快,即使是1毫秒你这个测试结果差距也会很大。

根据<<JAVA编程思想>>上说的,final在运行时候确实会有性能上的差异,但是呢,我们并不赞同从这个方面去勉强提高所谓的程序性能,而且在编译成class文件的时候,更智能的汇编器应该也会自动的解决这个问题。类似于c++中inline的语法把

final 确实会提高效率,但是原理我并不是很清楚,估计在百度上应该能搜出来。大概的原因有如下一些

  • final 变量在编译的时候可以被优化成常量或常数,从而提高性能(影响微小)

  • final 方法。相对于 C++ 来说,Java 方法默认是 virtual 的,所以会有方法链啊,动态绑定啊之类的事情要干,而 final 就是把方法申明为非 virtual 的,不再需要这些动态特性支持,从而提高性能

  • final 类是不可继承的类,大概也是能减少继承相关的一些处理吧

总的来说 final 能提高性能是对的,但是用 final 主要还是从静态检查的安全角度考虑,而不是从性能去考虑,除非实则项目中改成 final 之后性能有较高的提升。平时开发的时候对不需要改变的变量、类型添加 final 修饰还是个比较好的习惯,毕竟在需要的时候去掉 final 不会对以前的程序造成太大的影响,不过对方法加 final 就要慎重了。

新手上路,请多包涵

在java早期的时候,如果将一个方法指明为final,就是同意编译器将针对该方法的所有调用都转为内嵌调用,当编译器发现final方法调用命令时,它会根据自己谨慎的判断,跳过插入程序代码这种正常方法而执行方法调用机制(将参数压入栈,跳至方法代码处并执行,然后跳回并清理栈中的参数,处理返回值),并且以方法体中的实际代码的副本来代替方法调用。这将消除方法调用的开销。当然,如果一个方法很大,你的程序代码就会膨胀,因而可能开不到内嵌带来的任何的提高,因为,所带来的性能提高会因为花费于方法内的时间量而被缩减。在最近的java版本中,虚拟机(特别是hotspot技术)可以探测到这些情况,并且优化去掉这些效率反而降低的额外的内嵌调用,因此不再需要使用final方法来进行优化了。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题