4回复
3年前
一道面试题引发的对Java内存模型的一点疑问,第三部。
第一部在这里一道面试题引发的对Java内存模型的一点疑问?。
第二步在这里一道面试题引发的对Java内存模型的一点疑问,第二部。。
网友的讨论:
R大的回答:下面的代码 Java 线程结束原因是什么?
空无大神的回答:一个 println 竟然比 volatile 还好使?
知乎大湿的回答:java中volatile关键字的疑惑?。
我看了上面所有的回答,知道了代码死循环的原因是JIT做了激进优化。
但是我现在的疑问是,JIT做的这个优化有什么意义?优化都是为了提升效率,JIT的这个激进优化,效率提升体现在哪里?
JIT优化这行代码的意义是什么?JIT优化前的代码是这样,如下:
while(!stopRequested){
//每次循环都要去读取共享变量stopRequested的值,
//注意JIT优化前读取的是共享变量
}
JIT激进优化后的代码
boolean hoistedStopRequested = stopRequested;
while(!hoistedStopRequested){
//优化后的代码,还是每次循环都要去读取局部变量hoistedStopRequested的值。
//所以读取变量这个动作并没有被优化掉,只不过是把读取共享变量的动作
//换成了读取局部变量了。
//难道读取局部变量的速度比读取共享变量的速度要快吗?
}
所以我这里斗胆挑战一下权威,我感觉R大在知乎上面贴的JIT优化后代码
是不对的。自信来自知乎大湿的这篇回答:[java中volatile关键字的疑惑?](https://www.zhihu.com/question/263528143/answer/270308453)。
我认为JIT激进优化之后正确的代码应该是下面这个样子:
if (!stopRequested) {
//也就是说JVM觉得每次循环都去访问非volatile类型的stopRequested变量太浪费了,就只在函数执行之初访问一次stop,后续无论stop变量怎么变,都不管了。
while(true){//while循环的条件直接写死了。
}
}
这样优化才有意义,不知道我说的对不对?
第二个疑问:
我发现加了-Xint参数之后,就肯定不会出现死循环了。这是为什么呢?难道加了-Xint参数之后,线程每次循环的时候都会去主存中读取stopRequested 的值吗?这跟JMM规定的不太一样啊?JMM规定普通的共享变量存在于主内存当中,然后每个线程都有自己的工作内存。
我知道JMM只是一个内存模型规范,难道我禁用JIT之后,JVM就可以不遵守JMM规范了?
关联了该问题的文章:
4983 阅读