问题描述
您忘了声明guard
为易失性布尔值。
如果您将字段声明省略为volatile
,则不会告诉JVM该字段可以被多线程看到,例如您的示例。
在这种情况下,的值guard
将被读取一次,并且将导致无限循环。它将针对以下内容进行优化(无打印):
if(!guard)
{
while(true)
{
}
}
现在为什么要System.out.println
改变这种行为?因为writes
是同步的,这迫使线程不缓存读取。
这里粘贴了println
一种PrintStream
使用的方法的代码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;
}
}
注意同步。
解决方法
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教程学习并发性。找到了守卫的方块并尝试对其进行测试。我无法理解的一件事。
虽然循环是无限的,但是如果您取消注释threadMessage行,则一切正常。为什么?