共享变量的陈旧值

时间:2013-12-23 07:11:43

标签: java multithreading

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

  

没有可见性证明了不充分的方式   同步程序可能会导致令人惊讶的结果:过时的数据。当时   读者线程检查准备好了,它可能会看到过时的价值。除非   每次访问变量时都会使用同步,它是   可以看到该变量的陈旧值。更糟糕的是,陈旧性是   不是全部或全部:线程可以看到一个变量的最新值   但是第一个写的另一个变量的陈旧值

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

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

4 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:5)

  

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

来源DZone

硬件实施

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

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

另见:

What does volatile do?

答案 2 :(得分:3)

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

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

答案 3 :(得分:3)

此问题与memory visibility多线程问题有关。

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

public class XYZ{
   private String state;

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

}

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

  

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