当其他线程设置条件时,为什么Java中的空白不会中断? [英] Why does an empty while in Java not break when condition is set by other thread?

查看:138
本文介绍了当其他线程设置条件时,为什么Java中的空白不会中断?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在尝试对线程化类进行单元测试时,我决定使用主动等待来控制被测试类的行为.为此使用空的while语句无法达到我的预期.所以我的问题是:

While trying to unit test a threaded class, I decided to use active waiting to control the behavior of the tested class. Using empty while statements for this failed to do what I intended. So my question is:

为什么第一个代码不完整,而第二个代码不完整?

有一个类似的问题 ,但它没有真正的答案,也没有MCVE,而且更为具体.

There is a similar question, but it doesn't have a real answer nor an MCVE and is far more specific.

未完成:

public class ThreadWhileTesting {

    private static boolean wait = true;

    private static final Runnable runnable = () -> {
        try {Thread.sleep(50);} catch (InterruptedException ignored) {}
        wait = false;
    };

    public static void main(String[] args) {
        wait = true;
        new Thread(runnable).start();
        while (wait); // THIS LINE IS IMPORTANT
    }
}

完成:

public class ThreadWhileTesting {

    private static boolean wait = true;

    private static final Runnable runnable = () -> {
        try {Thread.sleep(50);} catch (InterruptedException ignored) {}
        wait = false;
    };

    public static void main(String[] args) {
        wait = true;
        new Thread(runnable).start();
        while (wait) {
            System.out.println(wait); // THIS LINE IS IMPORTANT
        }
    }
}

我怀疑Java编译器优化了while的空白,但是我不确定.如果有此行为,我该如何实现我想要的? (是的,由于我无法使用

I suspect that the empty while gets optimized by the Java compiler, but I am not sure. If this behavior is intended, how can I achieve what I want? (Yes, active waiting is intented since I cannot use locks for this test.)

推荐答案

wait不是易失性的,并且循环体为空,因此线程没有理由相信它将改变.这是准时结束的

wait isn't volatile and the loop body is empty, so the thread has no reason to believe it will change. It is JIT'd to

if (wait) while (true);

如果wait最初为true,则永远不会完成.

which never completes if wait is initially true.

简单的解决方案是制作wait volatile,这会阻止JIT进行此优化.

The simple solution is just to make wait volatile, which prevents JIT making this optimization.

关于第二个版本为何工作的原因:System.out.println是内部同步的;如 JSR133常见问题解答中所述:

As to why the second version works: System.out.println is internally synchronized; as described in the JSR133 FAQ:

在进入同步块之前,我们需要获取监视器,该监视器具有使本地处理器缓存无效的作用,以便可以从主内存中重新加载变量.

Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory.

因此,下次循环时将从主内存中重新读取wait变量.

so the wait variable will be re-read from main memory next time around the loop.

但是,您实际上并不能保证另一个线程中的wait变量的 write 已提交给主内存;因此,如上所述,@ assylias可能无法在所有情况下都起作用. (使变量volatile也可以解决此问题.)

However, you don't actually guarantee that the write of the wait variable in the other thread is committed to main memory; so, as @assylias notes above, it might not work in all conditions. (Making the variable volatile fixes this also).

这篇关于当其他线程设置条件时,为什么Java中的空白不会中断?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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