以下代码将始终打印出数据的“正确”值吗?即使在方法setData中将值分配给data和dataReady之间还有其他操作?
还是可以想象JVM重新排序这些操作,以便RunningThread可以将dataReady视为true,而数据仍为null?
如果该代码是安全且正确的,那么该可变字段如何防止重新排序问题呢?这是否意味着数据本身甚至不需要是易失性的,是否仅使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;
}
}
}
最佳答案
从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
写入之前,该线程发生在第二个线程读取dataReady
之前,而第二个线程读取data
。
换句话说,关于dataReady
变量的内存可见性保证足以防止读取data
,甚至不必将data
声明为volatile
。