为什么即使修改了锁变量,我也会得到一个无限的while循环? [英] Why do I get an infinite while loop even if I modify the lock variable?

查看:130
本文介绍了为什么即使修改了锁变量,我也会得到一个无限的while循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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所使用的PrintStreamprintln方法之一的代码的粘贴:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆