进入睡眠状态将重新加载Java寄存器中缓存的值?

时间:2019-03-10 10:14:22

标签: java multithreading jvm

在Java规范17.3睡眠和产量中

  

17.3睡眠和屈服

     

Thread.sleep使当前正在执行的线程在指定的时间段内进入睡眠状态(暂时停止执行),这取决于系统计时器和调度程序的精度和准确性。线程不会失去任何监视器的所有权,并且恢复执行将取决于调度和要在其上执行线程的处理器的可用性。

     

重要的是要注意Thread.sleep和Thread.yield都没有   同步语义。特别是,编译器不必刷新   在调用Thread.sleep之前,将缓存中的寄存器写出到共享内存中   或Thread.yield,在调用Thread.sleep或Thread.yield之后,编译器也不必重新加载缓存在寄存器中的值。

     

例如,在下面的(破碎)代码片段中,假定this.done是非易失性布尔字段:

while (!this.done)
    Thread.sleep(1000);
  

编译器可以自由读取一次this.done字段,并在每次循环执行中重用缓存的值。这意味着即使另一个线程更改了this.done

的值,循环也不会终止。

它描述了线程从不重新加载缓存在寄存器中的变量,但是当我运行以下代码时,它不起作用,循环终止

public class TestDemo {

    private  static boolean  keepRunning = true;

    public static void main(String[] args)  throws Exception {
        new Thread(
            ()->{
                while (keepRunning){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {

                    }
                }
                System.out.println("loop terminates");
            }
        ).start();
        Thread.sleep(1000);
        keepRunning = false;
        System.out.println("keepRunning is false now");
    }
}

结果是:

java spec 17.3中的代码有什么不同吗?

为什么在调用睡眠后重新加载字段keepRunning?

    C:\Users\LuoYY\Desktop>javac TestDemo.java

    C:\Users\LuoYY\Desktop>java TestDemo
    keepRunning is false now
    loop terminates

2 个答案:

答案 0 :(得分:1)

规范没有说编译器(或运行时)必须确保该字段永远不会重新加载或与其他线程同步。

  

“不必”,“可以自由”,“没有任何语义”

它只说允许这种行为(因为在性能优化中它是有意义的)。

因此,当涉及多个线程时,必须明确说明其工作方式:使其可变或使其成为线程局部的。

答案 1 :(得分:1)

再次阅读:

“编译器可以自由读取一次this.done字段”

是免费的表示它可以自行决定只读取一次,或每次都可以读取。就您而言,它每次都会读取,并且是规范所允许的合法行为。