为什么即使修改了锁变量,我也会得到一个无限的while循环?

问题描述

您忘了声明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行,则一切正常。为什么?

猜你在找的技术问答相关文章

如何检查配对的蓝牙设备是打印机还是扫描仪(Android)
是否允许实体正文进行HTTP DELETE请求?
如何将ZipInputStream转换为InputStream?
java.util.logging Java 8中的变量
PowerMockito.doReturn返回null
Java中的RESTful调用
Swing / Java:如何正确使用getText和setText字符串
特殊字符和重音字符
Android Studio中的ndk.dir错误
错误“找不到主类”