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;
    }
}

synchronized关键字除了用于保证代码段的原子性外,另外一个非常重要的意义在于对于线程共享变量修改的可视。
We want not only to prevent one thread from modifying the state of an object when another is using it, but also to ensure that when a thread modifies the state of an object, other threads can actually see the changes that were made.But without synchronization, this may not happen.

When a thread reads a variable without synchronization, it may see a stale value, but at least it sees a value that was actually placed there by some thread rather than some random value.This safety guarantee is called out-ofthin- air safety. Out-of-thin-air safety applies to all variables, with one exception: 64-bit numeric variables (double and long) that are not declared volatile

结论:
Locking is not just about mutual exclusion; it is also about memory visibility. To ensure that all threads see the most up-to-date values of shared mutable variables, the reading and writing threads must synchronize on a common lock.
互斥并不是加锁的唯一目的,还包含memory visibility。为了保证所有的线程能够访问到最新的共享变量的值,所有的读写共享变量的操作都需要对同一个对象加锁以保证同步

from Java Concurrency in Practice  By Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes,
Doug Lea