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");
}
}
C:\Users\LuoYY\Desktop>javac TestDemo.java
C:\Users\LuoYY\Desktop>java TestDemo
keepRunning is false now
loop terminates
答案 0 :(得分:1)
规范没有不说编译器(或运行时)必须确保该字段永远不会重新加载或与其他线程同步。
“不必”,“可以自由”,“没有任何语义”
它只说允许这种行为(因为在性能优化中它是有意义的)。
因此,当涉及多个线程时,必须明确说明其工作方式:使其可变或使其成为线程局部的。
答案 1 :(得分:1)
再次阅读:
“编译器可以自由读取一次this.done字段”
是免费的表示它可以自行决定只读取一次,或每次都可以读取。就您而言,它每次都会读取,并且是规范所允许的合法行为。