我在“实践中的Java并发”一书中看到了下面的例子。
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可能永远循环,因为就绪的值可能永远不会在读取器线程中可见。更奇怪的是,NoVisibility可以打印零,因为写入到就绪可能会在写入到数字之前被读者线程看到,这一现象被称为重新排序。
我能理解重新排序问题,但我无法理解可见性问题.为什么ready的值可能永远不会在读者线程中可见?一旦主线程用ready写入值,读取器线程迟早会有机会运行,并且可以读取ready的值。为什么ready中的主线程所做的更改可能对读取器线程不可见?
发布于 2015-07-26 04:52:05
ReaderThread的run()方法可能永远看不到ready的最新值,因为它可以自由地假设和优化该值不会在其线程之外发生变化。这种假设可以通过使用该语言的相关并发特性(如向ready声明中添加关键字volatile )来消除。
发布于 2015-07-26 06:30:04
我相信这是一个新的问题,它开始在多核CPU和单独的CPU缓存中发生。
如果您实际上是在读取和修改内存,则无需担心,即使使用多CPU,您也是安全的,除非每个CPU现在都有自己的缓存。内存位置将被缓存,而另一个线程将永远不会看到它,因为它将完全从缓存中运行。
当你使它不稳定时,它迫使两个线程每次都直接进入内存--所以它会使事情慢很多,但线程是安全的。
https://stackoverflow.com/questions/31633699
复制相似问题