我一直在阅读有关volatile在Java中使用变量的内容.据我所知,他们确保在不同核心/处理器上的系统中运行的所有线程的最新更新即时可见.但是,确保不会导致导致这些更新的操作的原子性.我看到经常使用以下文献
在每次读取同一字段之前,会发生对易失性字段的写入.
这是我有点困惑的地方.这是一段代码,可以帮助我更好地解释我的查询.
volatile int x = 0;
volatile int y = 0;
Thread-0: | Thread-1:
|
if (x==1) { | if (y==1) {
return false; | return false;
} else { | } else {
y=1; | x=1;
return true; | return true;
} | }
Run Code Online (Sandbox Code Playgroud)
由于x和y都是volatile,我们在边缘之前发生了以下事件
这是否意味着,在任何时候,只有一个线程可以在其"块"块中(因为写入会在读取之前发生)?
很可能Thread-0启动,加载x,找到它的值为0,就在它要在else-block中写y之前,有一个上下文切换到Thread-1,加载y找到它的值为0因此也进入了else-block.请问volatile针对这种上下文切换后卫(似乎不太可能)?
所以我认为这个问题在杂草中有一点,要点是volatile指示变量的值可能会在当前线程的范围之外发生变化,并且在使用之前必须始终读取其值.
原则上,您引用的语句实际上是在使用当前线程替换值之前,将读取该值.
你的例子是竞争条件,两个线程都可以返回true,也不能返回true,或者它们每个都可以返回一个不同的值 - 语义volatile不会为你的例子定义执行(我鼓励你编译并运行它)并看到输出变化).
说明行为的一种常用方法volatile是运行两个线程,其中一个线程更新共享状态并查看标记字段时发生的情况,以及何时不执行:
class VolatileTest implements Runnable
{
// try with and without volatile
private volatile boolean stopRunning = false;
public void triggerStop(){
stopRunning = true;
}
@Override
public void run(){
while(!stopRunning);
System.out.println("Finished.");
}
public static void main (String[] args) throws java.lang.Exception
{
final VolatileTest test = new VolatileTest();
new Thread(test).start();
Thread.sleep(1000);
test.triggerStop() = false;
}
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,未标记stopRunning为volatile可能导致while循环永远持续,因为除非stopRunning标记为volatile不需要读取每次迭代的值.