Java 共享变量的过时值

Java 共享变量的过时值,java,multithreading,Java,Multithreading,在阅读实践中的并发性时,我读到: NoVisibility充分展示了 同步程序可能会导致令人惊讶的结果:过时的数据。当 读卡器线程检查就绪,它可能会看到过期的值。除非 每次访问变量时都会使用同步,它是 可能会看到该变量的过时值。更糟糕的是,陈腐是一种浪费 不是全部或全无:线程可以看到一个变量的最新值 而是先写入的另一个变量的过时值 我不明白陈腐的意思。两个线程共享相同的引用,一个线程修改的值如何对另一个线程可见 每个线程都有自己的堆栈,因此它可以创建自己的变量副本 通道创建线程时,它复制所有 在

在阅读实践中的并发性时,我读到:

NoVisibility
充分展示了 同步程序可能会导致令人惊讶的结果:过时的数据。当 读卡器线程检查
就绪
,它可能会看到过期的值。除非 每次访问变量时都会使用同步,它是 可能会看到该变量的过时值。更糟糕的是,陈腐是一种浪费 不是全部或全无:线程可以看到一个变量的最新值 而是先写入的另一个变量的过时值

我不明白陈腐的意思。两个线程共享相同的引用,一个线程修改的值如何对另一个线程可见

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

来源

硬件实现

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

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

另见:


意思是在
main
中,意图是同时设置
number=42
ready=true
,但由于它们是按此特定顺序调用的,因此在
ReaderThread
中可能(可能会)存在竞争条件即使我们真的不想把号码打印出来


他们希望您将这两个变量同步到一起。

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

此问题与多线程的内存可见性问题有关

如果要读取/获取可由多个THRED修改的对象的值;那你就要小心了。让我们举一个例子来强调这一点:

public class XYZ{
   private String state;

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

上面的示例不同步返回状态的getter方法。因此,您可能会得到过时的数据(即使它是静态的)

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


它可能已经过时,更改将不可见。@NarendraPathai这是一个副本吗?@marounnaroun它提供了一些背景,收回了投票。但是两个线程都在同一个变量空间上运行。这样做是因为在读取值之后,一个线程会将其保存在缓存中并继续引用它。在这种情况下,其缓存中的值将如何得到修改??但两者都是静态变量,那么线程如何可能在其本地堆栈中维护它们,而修改后的值不会反映到其他线程?如果我没有错,对静态变量也是如此,因为Java中存在静态变量,处理器不知道这些变量。因此,对于处理器来说,它只是内存中一个由多个线程编辑的位置。但是只有该变量的一个副本,为什么不同的线程会有自己的副本呢?处理器缓存是硬件细节,与Java无关。是的,对于我们来说,内存中只有一个实例可以复制用于缓存目的。对于静态变量也是这样吗?在不同线程之间共享数据时,静态与否没有区别。只有局部变量没有这个问题,因为它们不能被共享。我不确定这是真的,至少对大多数CPU来说是这样。MESI协议应该处理与CPU缓存相关的一致性问题;但是,本书中的任何读者都会注意到,本书接着说:“NoVisibility可能会永远循环,因为ready的值可能永远不会对读者线程可见。”这需要涉及JVM内存模型的其他解释。
public class XYZ{
   private String state;

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