易失性写入是否确保在一个线程中发生的任何写入(非易失性/易失性写入)对其他线程都是可见的?
以下给定的代码是否总是生成90,80作为输出?
public class MyClass
{
private boolean flag = false;
private volatile int volatileInt = 0;
private int nonVolatileInt = 0;
public void initVariables()
{
nonVolatileInt = 90; // non-volatile write
volatileInt = 80; // volatile write
flag = true; // non-volatile write
}
public void readVariables()
{
while (flag == false)
{}
System.out.println(nonVolatileInt + ","+ volatileInt);
}
public static void main(String st[])
{
final MyClass myClass = new MyClass();
Thread writer = new Thread( new Runnable()
{
public void run()
{
myClass.initVariables();
}
});
Thread reader = new Thread ( new Runnable()
{
public void run()
{
myClass.readVariables();
}
});
reader.start();writer.start();
}
}我关心的是initVariables()方法。JVM不是可以自由地以以下方式重新排序代码块吗?
flag = true;
nonVolatileInt = 90 ;
volatileInt = 80;因此,我们将读取器线程的输出作为:0,0
或者,它们可以按以下方式重新排序:
nonVolatieInt = 90;
flag = true;
volatileInt = 80;因此,我们将读取器线程的输出作为:90,0
发布于 2014-05-05 11:04:19
易失性写入确保已执行的写入不会在此写入之后出现。但是,为了确保您看到了这一点,您需要首先执行易失性读取。
因此,我们将读取器线程的输出作为:
90,0
对,是这样。但是,如果正确执行读取操作,则无法获得0, 80
0, 0 - ok
90, 0 - ok
90, 80 - ok
0, 80 - breaks happens before.但是,您的读取不能确保在行为之前发生,因为它不会首先执行易失性读取。
System.out.println(nonVolatileInt + ","+ volatileInt);这首先读取非易失性字段,因此您可以看到非易失性字段的旧版本和易失性字段的新版本。
注意:实际上,你不太可能看到问题。这是因为缓存一次使整个缓存行失效,如果这些字段位于相同的64字节块中,则不应该看到不一致。
更有可能成为问题的是这个循环。
while (flag == false)
{}问题是,JIT可以看到线程嵌套写入flag,因此它可以内联该值。也就是说,它不需要读取值。这可能导致无限循环。
http://vanillajava.blogspot.co.uk/2012/01/demonstrating-when-volatile-is-required.html
https://stackoverflow.com/questions/23470842
复制相似问题