了解上下文切换期间的 Java 内存模型

Jav*_*ner 5 java multithreading java-memory-model

最近在一次会议演讲中,使用以下示例来演示多线程环境中的 Java 内存模型。

public class A {

    public static boolean done;

    public static void main(String[] args) throws InterruptedException {
        done = false;
        new Thread(new Runnable(){
            public void run() {
                System.out.println("running...");

                int count = 0;
                while (!done) {
                    count++;
                }

                System.out.println("Exiting thread");
            }
        }).start();

        System.out.println("in main...");
        Thread.sleep(2000);

        System.out.println("setting done to true");
        done = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道上面代码中创建的新线程永远不会退出,因为done变量被缓存在线程的本地缓存中。一个适当的解决方案是使done变量可变。

但是如果在while循环中,我们调用Thread.sleep()如下

    while (!done) {
        count++;
        try {Thread.sleep(0);} catch(Exception e){}
    }
Run Code Online (Sandbox Code Playgroud)

然后线程成功退出。

我的理解是,由于sleep(0)会发生上下文切换,这将使缓存条目无效,因此每次done检索的更新值。我的理解正确吗?这种行为也取决于机器的核心数吗?

Eug*_*ene 9

Java 语言规范明确指出Thread::sleep没有任何发生在之前的语义(而这些是您唯一想要推理的):

... Thread.sleep 和 Thread.yield 没有任何同步语义...

因此,规范不保证您“碰巧”看到使用它的任何输出。唯一可以保证你所做的当 volatile,再次,因为JLS为您提供了这种保证。

您对正确同步的程序的推理必须与发生前、上下文切换、缓存等无关。