求助>一道面试题引发的对Java内存模型的一点疑问?>
21回复
1周前

一道面试题引发的对Java内存模型的一点疑问?



image.png

如上图所示程序,按道理,子线程会通过num++操作破坏while循环的条件,从而终止循环,执行最后的输出操作。

但在我的多次运行中,偶尔会出现while循环一直不结束的场合。像我截图一样,程序一直不终止。

JDK7、JDK8均已试验,均能偶然触发。

1756 阅读
请先登录,再评论

回复列表

sofkyle1周前

答案由亮哥提供:
https://www.zhihu.com/question/263528143/answer/270308453

简单说来,是因为JIT激进编译导致的问题。

volatile只是恰巧阻止了JIT的激进编译,所以这里主要的问题不是可见性。因为哪怕变量不是volatile修饰,只要加上-Xint、-XX:-UseOnStackReplacement参数,问题一样不会出现。

1
._3762361周前

这样应该是变量可见性的问题

徐小白1周前

尝试跑了几遍,没跑出图中的结果。是不是还跟操作系统有关系的?

sofkyle1周前
回复 徐小白:

可以试试在num++前面加行Thread.sleep(1000)。

回复
瞭望1周前

按道理,子线程使用了system.out输出,system.out内部采用了syncronized同步,会触发num变量的主存同步,所以为什么还会出现死循环,感觉跟不同cpu mesi协议有关,可能mesi协议本事支持写入缓存未达到失效队列上限,所以导致主线程读取的num一直没有被失效

sofkyle1周前
回复 瞭望:

有相关资料能提供下吗,关于syncronized同步,会触发num变量的主存同步。以及mesi协议的失效队列?

回复
大空翼1周前

加一个-Xint再试试看😁

1
sofkyle1周前
回复 大空翼:

加-Xint、-XX:-UseOnStackReplacement都能解决问题。

回复
sofkyle1周前

我晕,忘记调度问题了。。。如果子线程先执行num++,那么主线程while循环就直接退出了。被带偏了。

Balloon1周前
回复 sofkyle:

主要还是volatile的问题

回复

变量前加个 volatile

1
sofkyle1周前
回复 亮哥:

这篇文章不错,感觉解决了我的问题。想点这个采纳的,但是发现回复不能采纳。😂

回复
亮哥1周前
回复 sofkyle:

有个更好的例子 在别的变量加volatile https://www.zhihu.com/question/263528143/answer/270308453

回复
亮哥1周前
回复 sofkyle:

因为jit优化导致的 while 会变成true ,解释执行情况下或关闭jit优化则不会进行优化 而且解释执行情况下getstatic指令是从内存读取值的。所以是始终可见,但因为cpu重排关系有可能不是实时可见 ,不好测

回复
查看更多