Java volatile是否读取刷新写入,并执行易失性写入更新读取

我理解read-acquire(不会在之后的后续读/写操作中重新排序)和write-release(不对其前面的读/写操作重新排序)。 我的q是: –

  1. 在读取获取的情况下,它之前的写入是否被刷新?
  2. 在写入释放的情况下,先前的读取是否会更新?

另外,read-acquire与volatile读取相同,而write release与Java中的volatile写入相同?

为什么这很重要的是,让我们来看看写释放的情况。

y = x; // a read.. let's say x is 1 at this point System.out.println(y);// 1 printed //or you can also consider System.out.println(x); write_release_barrier(); //somewhere here, some thread sets x = 2 ready = true;// this is volatile System.out.println(y);// or maybe, println(x).. what will be printed? 

此时,是x 2还是1? 在这里,考虑准备挥发性。 据我所知,volatile之前的所有商店都将首先显示出来……然后只有volatile才能显示出来。 谢谢。

参考: – http://preshing.com/20120913/acquire-and-release-semantics/

否:并非所有写入都被刷新,所有读取也都不会更新。

Java在multithreading的“先发生”基础上工作。 基本上,如果A发生在B之前,而B发生在C之前,那么A发生在C之前。所以你的问题等于x=2是否正式发生 – 在一些读取x的动作之前。

发生之前的边缘基本上是通过同步关系建立的,这些关系在JLS 17.4.4中定义。 有几种不同的方法可以做到这一点,但对于易失性,它基本上等于对易失性事件的写入 – 在读取相同的易失性之前:

  • 对易失性变量v(第8.3.1.4节)的写入与任何线程对v的所有后续读取同步 (其中“后续”根据同步顺序定义)。

鉴于此,如果您的线程写入ready = true ,那么单独写入并不意味着在它之前发生任何事情(就该写入而言)。 实际上恰恰相反; 写入ready发生在其他线程上的事情之前,如果他们ready

所以,如果另一个线程(设置x = 2设置x = 2 之后已经写好了,并且这个线程(你在上面发布) 然后读取ready ,那么它将看到x = 2 。 这是因为写入发生在读取之前,因此读取线程会看到写入线程已完成的所有操作(直到并包括写入)。 否则,你有一个数据竞争,基本上所有的赌注都是关闭的。

一些额外的说明:

  • 如果您没有事先发生的边缘,您可能仍会看到更新; 只是你不能保证。 所以,不要假设如果你没有读写ready ,那么你仍然会看到x = 1。 您可能会看到x = 1或x = 2,或者可能是其他一些写入(最多包括x = 0的默认值)
  • 在您的示例中, y始终为1,因为您不会在“somewhere here”注释后重新读取x 。 出于这个答案的目的,我假设在ready = true之前或之后有第二个y=x行。 如果没有,则y的值将与第一个println的值保持不变(假设没有其他线程直接更改它 – 如果它是局部变量则保证),因为线程内的动作总是看起来好像它们是没有重新订购。

Java内存模型未在“读取 – 获取”和“写入释放”方面指定。 这些术语/概念来自其他语境,正如您引用的文章非常清楚,它们经常被(由不同的专家)用来表示不同的事物。

如果你想了解挥发性物质在Java中是如何工作的,你需要了解Java内存模型和Java术语……(幸运的是)有充分理由并且精确指定1 。 尝试将Java内存模型映射到“读取 – 获取”和“写 – 释放”语义是一个坏主意,因为:

  • “读取 – 获取”和“写 – 释放”术语和语义没有明确规定,并且

  • 假设的JMM – >“读取 – 获取”/“写 – 释放”语义映射只是JMM的一种可能实现。 其他映射可能存在不同的,同样有效的语义


1 – …模数专家已经注意到某些版本的JMM存在缺陷。 但重点是,已经进行了认真的尝试,以提供理论上合理的规范……作为Java语言规范的一部分。

不,读取volatile变量不会刷新先前的写入。 可见操作将确保前面的操作可见,但读取volatile变量对其他线程不可见。

不,写入volatile变量不会清除先前读取值的缓存。 它只能保证刷新以前的写入。

在你的例子中,显然y在最后一行仍然是1。 根据前面的输出,只有一个赋值给y ,那个是1。 也许这是一个错字,你打算写println(x) ,但即使这样,2的值也不能保证可见。

对于您的第一个问题,答案是FIFO订单

对于你的第二个问题:请检查java中的Volatile Vs Static