重新排序volatile字段周围的正常字段

时间:2011-02-07 08:49:35

标签: java multithreading

基于

volatile有什么作用? http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#incorrectlySync

易失性的新保证 http://www.ibm.com/developerworks/library/j-jtp03304/

class VolatileExample {
  int x = 0;
  volatile boolean v = false;
  public void writer() {
    x = 42;
    v = true;
  }

  public void reader() {
    if (v == true) {
      //uses x - guaranteed to see 42.
    }
  }
}

似乎。

1a) write to non-volatile variable x 
1b) write to volatile variable v

1a永远不会移动传递1b

我想知道,如果我将源代码修改为以下

class VolatileExample {
  int x = 42;
  volatile boolean v = true;
  public void writer() {
    v = false;
    x = 0;
  }

  public void reader() {
    if (v == true) {
      //uses x - guaranteed to see 42?????
    }
  }
}

可以置换以下序列吗?

2a) write to volatile variable v
2b) write to non-volatile variable x

我想知道,2b可以在2a之前移动吗?这是因为如果2b能够在2a之前移动,读者就不能再保证在if块内看到42。

我觉得2b可以在2a之前根据以下信息移动。


http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#reordering

  

写入易失性字段有   与监视器相同的记忆效应   释放,并从一个不稳定的阅读   字段具有与a相同的记忆效果   监控获取。


  

这意味着任何内存操作   以前可以看到一个帖子   退出同步块是   任何线程进入后都可见   由...保护的同步块   同样的显示器,因为所有的记忆   操作在发布之前发生,   并且释放发生在之前   获得。


Roach Motels and The Java Memory Model

volatile_v = true;      <-- monitor release
non_volatile_x = 42;
(volatile_v will act as a roach motels, and it is fine for non_volatile_x to move into roach motels)


non_volatile_x = 42;
volatile_v = true;      <-- monitor release
(volatile_v will act as a roach motels, and it is not OK for non_volatile_x to move out from roach motels)

5 个答案:

答案 0 :(得分:1)

我们知道,对于任何先前的读取或写入(从Java5开始),对volatile变量的写入都不能重新排序,但反过来却不是这样。所以将程序重新排序为x = 0; v = false;根据我的理解,这是正确的。

在我们写到v之后,我们保证在读取v时,在写入v之前发生的每个动作都是可见的,但是在写入v之后没有说明任何动作 - 那些可能发生也可能没发生甚至可以在写入v之前重新排序。

答案 1 :(得分:0)

易失性有两个部分,指令的顺序和写入的“刷新”。

指令的顺序不会改变,但两段代码之间可能有任何延迟,所以在第二种情况下x可能是42但它可能是0.我的猜测是你会经常看到0。

根据您的体系结构,这可能比在其他系统上更有可能,因此在一台计算机上测试它是42,并不意味着它总是在另一台计算机上。

答案 2 :(得分:0)

据我了解新的内存模型,一旦将volatile值刷新到主内存,刷新线程可以看到的所有其他变量也必须刷新。但结果是你的2b不能被VM重新排序到2a之前,因为这会违反代码中隐含的'before-before'排序。

答案 3 :(得分:0)

我认为你没有保证,因为类实例字段 x 没有被封装,并且包可见可以被另一个线程更改。使 x 变量 volatile 可以解决该问题并保证所有线程的可见性。

答案 4 :(得分:0)

语句2b(写入非易失性变量x)可以在语句2a之前移动(写入volatile变量v),也就是说,另一个线程可能会看到v==truex==0)。

注意,即使没有重新排序另一个线程,也可能会看到这些值!

假设已创建并初始化VolatileExample的实例。线程T1在该实例上执行方法reader。它看到v == true并被调度程序中断。第二个线程调用方法writer现在可以执行分配v=falsex=0。当T1恢复并读取x时,它可能会读取值0(但没有保证看到0)。如果它看到值0,那么我们就会看到T1看到v==truex==0的情况。对于T1,看起来两个语句都已重新排序。由于可以在不重新排序的情况下观察到这种状态,因此实际上允许重新排序是有意义的。