多线程间,变量可见性问题。一个线程会永远看不到另一个线程的更新吗?

作者说,由于读线程可能永远发现不了main对ready变量的修改就会永远循环下去,但是貌似不太可能永远读不到main对ready变量修改之后的值吧,可能会由于从栈区复制回堆区时,有几毫秒的误差,read线程读到的是旧值,但堆区值更新之后,read线程就读到了新值了吧,为什么说会永远循环下去呢?图片说明

再回去又读了一遍,有如下解释:
根据JVM设置,如果设置成server模式会有指令重排,如上述循环判断就会变成if(!ready){while(true){...}}所以就会造成死循环,如果设置成volatile,JVM就不会对这个变量进行指令重排。

亲测,线程是能读取到ready值的改变的,可以正常的结束
并且,看代码没有问题啊,应该不会出现读取不到ready值改变的情况的,一般通过旗标来关闭线程都是这样来操作的。

附上测试代码

public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}

除非线程没有去真正读取更新后的数据,比如一直读的寄存器等。那么就可能读取不到新数据

这是JAVA并发编程实践 第三章开头的一个例子,是并发编程的经典教材,按道理作者应该不会说错。
但是为何我在jdk1.7下出来的结果,以及根据我的理解,都不太可能永远死循环。
求合理解释

把打印方法注释,因为打印方法里存在synchronized代码块,在获得同步锁和释放同步锁的同时,会将工作内存刷入到主内存中。所以,会导致,不是用volatile关键字,该线程变量对其他线程变量也是可见的。仅是个人理解,有不周到之处请多多指教,谢谢。

package com.dsc.test;

public class VolatileTest {

public static void  main(String args[]) throws InterruptedException {
    SumThread sumThread = new SumThread();
    new Thread(()->{
        sumThread.run();
    }).start();
    Thread.sleep(1000);

   sumThread.setController(false);
    System.out.println("已经修改,结束运行");
}

static class SumThread {
private boolean controller=true;

   public void setController(boolean controller) {
       this.controller = controller;
   }

   public void run(){
        while(controller){
           // System.out.println();
           /*
            把打印方法注释,因为打印方法里存在synchronized代码块,在获得同步锁和释放同步锁的同时,
            会将工作内存刷入到主内存中
            public void println(boolean x) {
                synchronized (this) {
                    print(x);
                    newLine();
                }
            }*/
        }
        System.out.println("已经被修改");
    }


}

}