是否可以重新排序将值连续分配给多个易失性字段的操作?

时间:2015-05-19 12:37:11

标签: java concurrency thread-safety volatile java-memory-model

以下代码是否会打印出"更正" 数据的价值?即使在方法 setData 中将值分配给数据 dataReady 之间还有其他操作?

或者JVM是否可以重新订购这些操作,以便 RunningThread 可以看到 dataReady 为真,而数据仍为空?

如果代码是安全的&对于一个阻止重新排序问题的易失性字段,它是什么?这是否意味着数据本身甚至不需要是易变的,只有使 dataReady 易失性导致JVM不缓存本地值一个字段易失的实例的其他字段?

public class RunningThread implements Runnable {

private volatile boolean dataReady = false;
private volatile String data = null;

public void run() {
    while (!dataReady){
        //Do stuff or wait
    }
    System.out.println("Value of data '" +data +"' is definitely not null.");
}


//setData called by another thread
public void setData(String dataToSet){
    if (dataToSet!=null){
        data = dataToSet;
        dataReady = true;
    }
}

}

1 个答案:

答案 0 :(得分:3)

在写入volatile变量之前,线程执行的所有写操作在读取前一个线程已写入的volatile变量的值后,将对另一个线程可见。

Java Language Specification的措辞是:

  

如果 x y 是同一个线程的操作, x 按照程序顺序出现在 y 之前,然后 hb(x,y)

     

...

     

如果 hb(x,y) hb(y,z),那么 hb(x,z)

     

...

     

volatile字段(§8.3.1.4的写入发生在每次后续读取该字段之前。

所以对data 的写入发生在同一个线程写入dataReady 发生之前 - 第二个线程读取{{1 发生在第二个线程读取dataReady之前。

换句话说,关于data变量的内存可见性保证足以保证读取dataReady,甚至不必将data声明为data }。