17.3睡眠和产量
Thread.sleep导致当前正在执行的线程在指定的持续时间内休眠(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。该线程不会失去任何监视器的所有权,并且恢复执行将取决于调度和执行该线程的处理器的可用性。
值得注意的是,Thread.sleep和Thread.yield都没有任何同步语义。特别是,编译器不必在调用Thread.sleep或Thread.yield之前将寄存器中缓存的写入刷新到共享内存,编译器在调用Thread.sleep或Thread之后也不必重新加载缓存在寄存器中的值。让。
例如,在以下(损坏的)代码片段中,假设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
规范并未说明编译器(或运行时)必须确保该字段永远不会重新加载或与其他线程同步。
“不必”,“是免费的”,“没有任何语义”
它只表示允许这样的行为(因为它在性能优化中有意义)。
所以当涉及多个线程时,你必须明确它应该如何工作:要么使它变为volatile,要么使它成为线程局部的。
再读一次:
“编译器可以自由阅读this.done中的字段一次”
是免费的意味着它只能读一次,或者每次都可以自行阅读。在您的情况下,它每次都会读取,这是规范允许的合法行为。