除非我在其中放入System.out.println(),否则循环不起作用

时间:2015-07-13 16:42:25

标签: java

在图形类中,我有它,所以当你按“m”时它会使布尔值为M,然后我就有了这段代码。

graphic.m = false;
while(graphic.m == false){
}
graphic.m = false;

它不起作用,它不会在它之前继续使用代码。

但如果我这样做

graphic.m = false;
while(graphic.m == false){
System.out.println("m");
}
graphic.m = false;

它完美地运作,有人可以解释为什么以及如何通过这个?

2 个答案:

答案 0 :(得分:3)

为了实现这一目标,其他一些主题必须将graphic.m设置为true。所以我认为这种情况正在发生。

我的猜测是graphic.m不是一个易变的字段。这意味着在写入它的一个线程(从另一个线程将其设置为true)与从中读取的另一个线程(您拥有的代码)之间没有正式发生的关系。 JVM可以自由地在线程中缓存值(或让CPU核心缓存它们等),并且似乎正在这样做。

System.out.println是一种同步方法。即使根据JLS对graphic.m没有任何形式上的影响,发布/获取同步锁的行为很可能会在内核之间刷新内存,这样你的线程就会看到{{1}最近的价值。要强调:这不是发生的Java规范,你不应该依赖于这种行为 - 如果你这样做,你可能会被一个难以接受的东西咬伤捕获JVM的某些未来版本中的错误,或稍微不同的硬件等。

解决方案是使graphic.m成为graphic.m字段(或通过同步方法获取/设置它,或使用AtomicBoolean)。

答案 1 :(得分:0)

您需要包含volatile关键字,以确保跨线程可见变量的可见性。

当线程对非易失性变量进行操作时,每个变量都可能会在处理它们时将这些变量从主内存复制到自己的CPU缓存中。对于非易失性变量,JVM不保证它将从主存储器或CPU高速缓存读取数据,或者它将从CPU高速缓存写回主存储器。

如果声明变量volatile,JVM会确保所有读取都来自主内存,所有写入也都是主内存。

System.out可能有助于刷新CPU缓存。它是一种同步方法,所以我认为它的锁定会给JVM时间。