为什么即使修改了锁变量,我也会得到一个无限的while循环? [英] Why do I get an infinite while loop even if I modify the lock variable?
问题描述
public class GuardedBlock {
private boolean guard = false;
private static void threadMessage(String message) {
System.out.println(Thread.currentThread().getName() + ": " + message);
}
public static void main(String[] args) {
GuardedBlock guardedBlock = new GuardedBlock();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
guardedBlock.guard = true;
threadMessage("Set guard=true");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
threadMessage("Start waiting");
while (!guardedBlock.guard) {
//threadMessage("Still waiting...");
}
threadMessage("Finally!");
}
});
thread1.start();
thread2.start();
}
}
我正在通过Java Essentials教程学习并发性.找到了守卫的方块并尝试对其进行测试.我无法理解一件事.
I was learning concurrency through java essentials tutorial. Got to guarded blocks and tried to test it. There is one thing I cannot understand.
虽然循环是无限的,但是如果取消注释threadMessage行,则一切正常.为什么?
While loop is infinite, but if you uncomment threadMessage line everything works fine. Why?
推荐答案
简短答案
您忘记将guard
声明为易失性布尔值.
You forgot to declare guard
as a volatile boolean.
如果您将字段声明省略为volatile
,则不是在告诉JVM该字段可以被多线程看到,在您的示例中就是这种情况.
If you ommit the declaration of your field as volatile
, you are not telling the JVM that this field can be seen by multiple thread which is the case in your example.
在这种情况下,guard
的值将仅读取一次,并且将导致无限循环.它将被优化为类似这样的内容(无打印):
In such cases, the value of guard
will be read only once and will cause an infinite loop. It will be optimized to something like this (without the print) :
if(!guard)
{
while(true)
{
}
}
现在为什么System.out.println
会更改此行为?因为writes
已同步,这迫使线程不缓存读取.
Now why System.out.println
change this behaviour ? Because the writes
are synchronized which force the threads to not cache reads.
这是System.out.println
所使用的PrintStream
的println
方法之一的代码的粘贴:
Here a paste of the code of one of the println
method of PrintStream
used by System.out.println
:
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
和write
方法:
private void write(String s) {
try {
synchronized (this) {
ensureOpen();
textOut.write(s);
textOut.flushBuffer();
charOut.flushBuffer();
if (autoFlush && (s.indexOf('\n') >= 0))
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
注意同步.
这篇关于为什么即使修改了锁变量,我也会得到一个无限的while循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!