无法理解Java中volatile的语义

Hun*_*Tux 4 java volatile

我一直在阅读有关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,我们在边缘之前发生了以下事件

  1. 在Thread-0中写入y和在Thread-1中读取y之间
  2. 在Thread-1中写入x和在Thread-0中读取x之间

这是否意味着,在任何时候,只有一个线程可以在其"块"块中(因为写入会在读取之前发生)?

很可能Thread-0启动,加载x,找到它的值为0,就在它要在else-block中写y之前,有一个上下文切换到Thread-1,加载y找到它的值为0因此也进入了else-block.请问volatile针对这种上下文切换后卫(似乎不太可能)?

Mar*_*iot 5

所以我认为这个问题在杂草中有一点,要点是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)

在此示例中,未标记stopRunningvolatile可能导致while循环永远持续,因为除非stopRunning标记为volatile不需要读取每次迭代的值.