订购前的易失性变量和重复

我有两个主题:

主题:1

a = 1; x = b; 

主题:2

 b = 1 y = a 

这里a和b被声明为volatile。 我不明白在a = 1之间如何创建“before-before”边缘; 和y = a; 在x = b之间; 和b = 1;

我知道通过使用volatile变量可以防止从线程缓存中读取过时值。 但是,在订购之前,如何确保变量发生变化。

具体来说,我不明白这一点:

在每次后续读取相同字段之前发生对易失性字段的写入。

锄头有用吗?

在每次后续读取相同字段之前发生对易失性字段的写入。

这里重要的词是“后续”。

以下是Java语言规范17.4.4同步顺序的相关部分 :

每次执行都有一个同步顺序。 同步顺序是执行的所有同步动作的总顺序。 对于每个线程t,t中同步动作(第17.4.2节)的同步顺序与t的程序顺序(第17.4.3节)一致。 同步动作引发与动作的同步关系,定义如下:

  • […]
  • 对volatile变量(第8.3.1.4节)的写入v与任何线程对v的所有后续读取同步(其中后续根据同步顺序定义)。

请注意最后一部分。 所以它说如果你考虑程序动作的任何总排序,那么读取总顺序中的一个易失性变量而不是写入不能“错过”写入。

要进行分析,首先列出所有可能的同步订单。 它们必须与编程顺序一致。 在您的示例中,有6个可能的订单。

  1 2 3 4 5 6 w(a) w(a) w(b) w(a) w(b) w(b) r(b) w(b) w(a) w(b) w(a) r(a) w(b) r(b) r(b) r(a) r(a) w(a) r(a) r(a) r(a) r(b) r(b) r(b) 

每个订单都建立了一些先发生过的关系。 在(1)中,我们有w(a)发生在r(a)之前。 在(6)中,我们有w(b)发生在r(b)之前。 在(2) – (5)中,我们都有。

对于每个可能的顺序 ,给定由它建立的先发生关系,您需要分析执行以确保它执行您想要的操作。

如果这听起来太难了,那就是。 在现实生活中,我们通常用简单的情况限制自己,其中只锁定/释放一个对象,或者只读取和写入一个volatile变量。 然后它不是太复杂。

在每次后续读取相同字段之前发生对易失性字段的写入。

这段文字令人困惑。 它将发生之前的关系限制为在读取之前发生的写入! 它只说在之后发生的读取,实际发生在之后。

换句话说,它试图说的是写入期间不会发生读取,并且如果在写入之后存在导致读取发生的其他发生之前的关系,则读取将具有以下值:那写。

请参阅JLS部分17.4.4同步顺序 ,该顺序在此上下文中定义单词“后续”。