Java:无限while循环中的if语句
我是 Java 新手,以下内容可能是显而易见的,但令我感到困惑。考虑以下代码:
while(1>0){
if(x!=0){
//do something
}
}
x 变量在不同的线程中更改。但是,即使 x 不为零,if 语句中的代码也永远不会执行。如果我通过以下方式更改代码,
while(1>0){
System.out.println("here");
if(x!=0){
//do something
}
}
则当 x 不再为零时,现在将执行 if 语句中的代码。我怀疑这与Java编译器的规则有关,但这让我很困惑。任何澄清这一点的帮助将不胜感激。
I am new to Java and the following might be obvious, but it is puzzling to me. Consider the following code:
while(1>0){
if(x!=0){
//do something
}
}
The x variable is changed in a different thread. However, the code in the if statement is never executed even when x is not zero. If I change the code by the following
while(1>0){
System.out.println("here");
if(x!=0){
//do something
}
}
the code in the if statement is now executed when x is no longer zero. I suspect this has to do with the rules of the Java compiler, but it is very confusing to me. Any help clarifying this would be greatly appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果 x 在不同的线程中发生变化,那么您可能会看到由于未同步对该变量的访问而产生的副作用。
Java 内存和线程模型非常复杂,因此我建议您获取 Java 的副本Brain Goetz 的并发实践,请阅读。
简短的答案是确保对
x
的访问包含在synchronized
块中:在修改
x
的代码中也是如此。请注意,此示例将
x
存储在临时变量中,因为您希望同步块尽可能小 - 它们强制执行互斥锁,因此您不想在其中执行太多操作。或者,您可以将
x
声明为易失性
,这可能足以满足您的用例。我建议您使用synchronized
版本,因为您最终需要知道如何正确使用synchronized
,所以您不妨现在就学习它。If
x
is changing in a different thread then you are probably seeing a side-effect of the fact that you have not synchronized access to that variable.The Java memory and threading model is pretty complex, so I'd recommend you get a copy of Java Concurrency in Practice by Brain Goetz and have a read.
The short answer is to make sure that access to
x
is enclosed in asynchronized
block:And similarly in the code that modifies
x
.Note that this example stores
x
in a temporary variable, because you want synchronized blocks to be as small as possible - they enforce mutual exclusion locks so you don't want to do too much in there.Alternatively, you could just declare
x
to bevolatile
, which will probably be sufficient for your use case. I'd suggest you go with thesynchronized
version because you'll eventually need to know how to usesynchronized
properly, so you might as well learn it now.如果您使用多线程代码,请检查 x 变量是否是易失性的。
If you are using multithreading code, check that x variable is volatile.
Cameron Skinner 的回答很好地解释了没有
System.out.println("here");
就不会发生任何事情的原因。那么为什么当使用
println
时,if(x!=0)
内的块会起作用呢?println
执行一个synchronized
块(请参阅PrintStream.write(String s)
)。这会强制当前线程从主内存检索 System.out 状态并更新线程的缓存,然后再让线程执行任何进一步的代码行。令人惊讶的副作用是,其他变量的状态(例如您的x
)也会以这种方式更新,尽管x
的锁不参与同步。这称为搭载。如果我使用自由文本来描述 Java Memory 中描述的形式模型规范:表示在释放锁之前执行的操作发生在在下次获取该锁之后执行的操作。
我将用一个例子来演示它。假设
线程 1
已执行,并且只有当它完成时,线程 2
才会启动。还假设 x、y 和 z 是两个线程共享的变量。请注意,我们只能在y
的synchronized
块内确定z
的值。这当然是一种非常糟糕的做法来依赖同步......
Th reason nothing happens without the
System.out.println("here");
is well explained by Cameron Skinner's answer.So why does the block inside the
if(x!=0)
works whenprintln
is used?println
executes asynchronized
block (seePrintStream.write(String s)
). This forces the current thread to retrieveSystem.out
state from the main memory and update the thread's cache, before letting the thread to execute any further line of code. The surprising side effect, is that also states of other variables, such as yourx
, are also updated in this manner, althoughx
's lock was not involved in the synchronization. It's called piggybacking.If I'll use free text to describe the formalities described in the Java Memory Model Specification: it is said that operations executed before a release of a lock happen-before operations executed after the next obtaining of that lock.
I'll demonstrate it with an example. Assume that
Thread 1
is executed and only when it finishes,Thread 2
is started. Also assume thatx
,y
andz
are variables shared by both threads. Note that we can determinez
's value only inside thesynchronized
block ofy
.This is of course a very bad practice to rely on for synchronization...
这可能是编译器优化。它认识到,在 while 循环的范围内,变量永远不会改变,并且会缓存该值,而不是每次都从内存中读取它。为了避免这种行为,只需将变量声明为 volatile:
This is likely a compiler optimization. It recognizes that, within the scope of your while loop, the variable never changes and will cache the value rather than reading it from memory each time. In order to avoid this behavior, simple declare the variable as volatile:
还要检查您在 if 子句中所做的事情。如果它们只是内存操作,那么它比写入控制台要快得多,因此在更改状态之前,您在最后一种情况下执行了更多操作。
Check also what you are doing inside if clause. It they are only memory operations it is a hell lot faster than writing to console, so you are executing much more operations in last case before changing state.