2 qq 30680953 qq_30680953 于 2016.03.15 13:57 提问

多线程间,变量可见性问题。一个线程会永远看不到另一个线程的更新吗?

作者说,由于读线程可能永远发现不了main对ready变量的修改就会永远循环下去,但是貌似不太可能永远读不到main对ready变量修改之后的值吧,可能会由于从栈区复制回堆区时,有几毫秒的误差,read线程读到的是旧值,但堆区值更新之后,read线程就读到了新值了吧,为什么说会永远循环下去呢?图片说明

5个回答

qq_30680953
qq_30680953   2016.03.16 08:49
已采纳

再回去又读了一遍,有如下解释:
根据JVM设置,如果设置成server模式会有指令重排,如上述循环判断就会变成if(!ready){while(true){...}}所以就会造成死循环,如果设置成volatile,JVM就不会对这个变量进行指令重排。

qq_30680953
qq_30680953 还是无法出现无限循环的样子,理论上的原因是知道了。无法实践。
一年多之前 回复
daidaineteasy
daidaineteasy   Ds   Rxr 2016.03.15 14:58

亲测,线程是能读取到ready值的改变的,可以正常的结束
并且,看代码没有问题啊,应该不会出现读取不到ready值改变的情况的,一般通过旗标来关闭线程都是这样来操作的。

daidaineteasy
daidaineteasy 回复qq_30680953: 嘿嘿,也是对这上面说的内容感到疑惑,所以就自己动手试了试。因为之前一直用ready这种的旗标来退出线程,这上边说可能会永远读不到,所以就想看看啥情况。
一年多之前 回复
qq_30680953
qq_30680953 给力。。。忘了贴代码给大家测试了,谢谢。。
一年多之前 回复
qq_30680953
qq_30680953   2016.03.15 15:13

附上测试代码

public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
oyljerry
oyljerry   Ds   Rxr 2016.03.15 15:25

除非线程没有去真正读取更新后的数据,比如一直读的寄存器等。那么就可能读取不到新数据

qq_30680953
qq_30680953   2016.03.15 16:07

这是JAVA并发编程实践 第三章开头的一个例子,是并发编程的经典教材,按道理作者应该不会说错。
但是为何我在jdk1.7下出来的结果,以及根据我的理解,都不太可能永远死循环。
求合理解释

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!