2010-10-19 44 views
12

之前发生了,我有两个线程:volatile变量和订购

主题:1

a = 1; 
x = b; 

主题:2

b = 1 
y = a 

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

我明白,通过使用volatile变量,可以防止从线程缓存读取陈旧值。但是,如何确保在订购之前发生易失变量。

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

到挥发性现场写的 同一领域的每一个后续读之前发生 。

锄头能行吗?

+0

看到这个最近的问题和答案的很多相关的信息:http://stackoverflow.com/questions/3964317/memory-barriers-and-coding-style-over-a-java-vm – andersoj 2010-10-19 18:43:36

回答

15

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

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

这里的Java语言规范17.4.4 Synchronization Order的相关位:

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

  • [...]
  • 于挥发性变量A写(§8.3.1.4)V同步-与所有后续读取的v由任何线程(其中随后根据同步顺序定义)。

请注意最后一部分。所以这就是说,如果考虑程序行为的任何总排序,任何在整个排序中写入的易失性变量的读取都不会“错过”写入。

+0

“*对于每个线程t *,同步动作的同步顺序...“易变本身并不决定线程之间的同步顺序吗? – 2010-10-19 17:47:54

+0

我也有同样的问题。发现java spec有点神秘。 – devnull 2010-10-19 18:04:59

+1

@pst:易失性操作* total *顺序,而不是特定线程的顺序。它实际上意味着一个线程无法读取一个volatile变量而不检查其他线程是否执行了写操作。 – 2010-10-19 18:21:01

3

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

这段文字是令人困惑的。它限制了发生之前发生的事情 - 在读之前!它只是说,读取之后发生,实际上发生在之后。

换句话说,它试图说的是,在写入过程中,读取不会发生,并且如果还有其他发生 - 在写入之后导致读取发生的关系之前,读取将具有该写入的值。

请参阅JLS部分17.4.4 Synchronization Order,它在此上下文中定义单词“后续”。

3

要分析,首先列出所有可能的同步顺序。他们必须符合编程顺序。在你的例子中,有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)中,我们都有。

对于每一个可能的订单,考虑到由它建立之前发生的关系,你需要分析执行,以确保它做你想做的。

如果这听起来太难了,它是。在现实生活中,我们通常仅限于简单的情况,其中只有一个对象被锁定/释放,或者只有一个易失性变量被读取和写入。然后它不是太复杂。