java 并发编程中的可见性问题
Visibility issue in java concurrent programming
我在书 '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)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
进一步表述为:
NoVisibility could loop forever because the value of ready might never become
visible to the reader thread. Even more strangely, NoVisibility could print
zero because the write to ready might be made visible to the reader thread before
the write to number, a phenomenon known as reordering.
我能理解重新排序问题,但我无法理解可见性问题。为什么 ready
的值可能永远不会对 reader 线程可见?一旦主线程在 ready
中写入值,迟早 reader 线程将有机会 运行 并且它可以读取 ready
的值。为什么主线程在 ready
中所做的更改可能对 reader 线程不可见?
ReaderThread
的 run()
方法可能永远看不到 ready
的最新值,因为它可以自由假设和优化该值不会在其线程外更改。这个假设可以通过使用语言的相关并发特性来消除,比如在 ready
的声明中添加关键字 volatile
。
我认为这是一个新问题,开始出现在多核 CPU 和单独的 CPU 缓存中。
如果您实际上正在读取和修改内存,则无需担心,即使使用多个 CPU 也是安全的,只是每个 CPU 现在都有自己的缓存.内存位置将被缓存,其他线程将永远看不到它,因为它将专门在缓存之外运行。
当你让它变易变时,它会强制两个线程每次都直接进入内存——所以它会减慢速度,但它是线程安全的。
我在书 '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)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
进一步表述为:
NoVisibility could loop forever because the value of ready might never become visible to the reader thread. Even more strangely, NoVisibility could print zero because the write to ready might be made visible to the reader thread before the write to number, a phenomenon known as reordering.
我能理解重新排序问题,但我无法理解可见性问题。为什么 ready
的值可能永远不会对 reader 线程可见?一旦主线程在 ready
中写入值,迟早 reader 线程将有机会 运行 并且它可以读取 ready
的值。为什么主线程在 ready
中所做的更改可能对 reader 线程不可见?
ReaderThread
的 run()
方法可能永远看不到 ready
的最新值,因为它可以自由假设和优化该值不会在其线程外更改。这个假设可以通过使用语言的相关并发特性来消除,比如在 ready
的声明中添加关键字 volatile
。
我认为这是一个新问题,开始出现在多核 CPU 和单独的 CPU 缓存中。
如果您实际上正在读取和修改内存,则无需担心,即使使用多个 CPU 也是安全的,只是每个 CPU 现在都有自己的缓存.内存位置将被缓存,其他线程将永远看不到它,因为它将专门在缓存之外运行。
当你让它变易变时,它会强制两个线程每次都直接进入内存——所以它会减慢速度,但它是线程安全的。