我刚刚阅读了 Java Concurrency in Practice 一书,它显示了一个不安全的程序:
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready) <=== synchronized ?
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42; <=== synchronized ?
ready = true; <=== synchronized ?
}
}
书中写道:
同步还有另一个重要且微妙的方面:内存可见性。我们不仅要防止一个线程在另一个正在使用对象时修改它的状态,还要确保当一个线程修改一个对象的状态时,其他线程可以实际看到所做的更改。但如果没有同步,这可能不会发生。
所以我明白即使没有并发写入,线程之间共享的数据,比如一个线程写入另一个线程读取,也需要同步,以便由写入线程发布到读取线程。写入线程可以启动另一个线程,该线程将在启动读取线程后循环读取写入线程写入的数据。数据可以共享,也可以不共享。如果数据是多个变量,则可能会共享一些变量而不会共享其他变量,并且共享顺序可能会有所不同。线程之间共享的所有数据都应该同步。如果下面的程序没有使用同步块,那么读取线程可能看不到ready true,或者它可能在看到它的数字集后才看到它。未同步的数据对于线程来说会变得陈旧。为避免数据过时,它必须在写访问期间和读访问期间同步。仅同步写入访问不会防止数据过时。
我想知道如何使用 synchronize 语句来使这个示例程序安全。