共享变量的陈旧值

在实践中阅读并发时,我读到了这一点

No Visibility演示了不完全同步的程序可能导致令人惊讶的结果的方式:陈旧的数据。当读者线程检查准备好时,它可能会看到过时的值。 除非每次访问变量时都使用同步,否则可能会看到该变量的陈旧值。 更糟糕的是,陈旧不是全部或全无:线程可以看到一个变量的最新值,但是第一个写入的另一个变量的陈旧值

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

我没有得到陈旧的意思。 两个线程共享相同的引用,如何修改一个值永远不会被其他线程看到?

它的主要意图是在同一时间设置number = 42和ready = true,但由于它们是按照这个特定的顺序调用的,因此你的ReaderThread存在竞争条件,它可能(可能会)打印出这个数字即使我们真的不想要它。

他们希望您同步这两个设置在一起的变量。

这不是Java特定的问题。 处理器有缓存。 如果没有同步,处理器1可以从内存中读取一个值到其缓存中,在其缓存中修改它但从不刷新它,然后处理器2从内存读取过时值

每个线程都有自己的堆栈 ,因此它可以访问自己的变量副本。 创建线程时,它会将所有可访问变量的值复制到其自己的内存中。 volatile关键字用于对jvm说“ 警告,此变量可以在其他线程中修改 ”。 如果没有此关键字,JVM可以自由地进行一些优化,例如从不在某些线程中刷新这些本地副本。 volatile强制线程更新每个变量的原始变量。

来源DZone

硬件实现

这是因为为快速访问变量而进行的处理器优化。 当变量保存在缓存中时,访问速度比每次访问内存要快得多。 因此,为了刷新缓存,您需要说volatile并刷新缓存并重建它,因为此变量正在其他线程中进行修改。

static变量的缓存也已完成,由于快速访问的相同原因,它们也有资格进行缓存。 所以是的,你也需要对static变量进行volatile

也可以看看:

挥发性有什么作用?

此问题与multithreading的memory visibility问题有关。

如果你想读取/获取一个可被多个threds修改的对象的值; 那你需要小心。 让我们举一个示例来强调这一点:

 public class XYZ{ private String state; public synchronized setState(..){ //set state } public String getState(){ return state; } 

}

上面的示例不同步返回状态的getter方法。 所以你可能得到陈旧的数据(即使它是静态的)

获取最新数据的唯一方法是同步get方法或将状态声明为volatile。