我有两个主题:
主题:1
a = 1;
x = b;
主题:2
b = 1
y = a
这里a和b被声明为volatile。我不明白在a = 1之间如何创建“before-before”边缘;和y = a;在x = b之间;和b = 1;
据我所知,通过使用volatile变量,可以防止从线程缓存中读取过时值。但是,在订购之前,如何确保变量发生变化。
具体来说,我不明白这一点:
发生对易失性字段的写入 在每次后续阅读之前 相同的领域。
锄头有用吗?
答案 0 :(得分:16)
对易失性字段的写入发生在每次后续读取同一字段之前。
这里的重要词是“后续”。
以下是Java语言规范17.4.4 Synchronization Order的相关部分:
每次执行都有一个同步顺序。同步顺序是执行的所有同步动作的总顺序。对于每个线程t,t中同步动作(第17.4.2节)的同步顺序与t的程序顺序(第17.4.3节)一致。 同步动作引发与动作的同步关系,定义如下:
- [...]
- 对volatile变量(第8.3.1.4节)的写入v与任何线程的v的所有后续读取同步(其中后续根据同步顺序定义)。
请注意最后一部分。所以它说如果你考虑程序动作的任何总排序,那么读取总顺序后面的一个易失性变量而不是写入就不能“错过”写入。
答案 1 :(得分:4)
要分析,首先列出所有可能的同步订单。它们必须与编程顺序一致。在您的示例中,有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)中,我们都有。
对于每个可能的订单,给定由它建立的先发生关系,您需要分析执行以确保它能够满足您的需求。
如果这听起来太难了,那就是。在现实生活中,我们通常局限于简单的情况,其中只有一个对象被锁定/释放,或者只有一个易失性变量被读写。然后它不是太复杂。
答案 2 :(得分:3)
写入易失性字段发生在每次后续读取同一字段之前。
这篇文章令人困惑。它将发生之前的关系限制为在读取之前发生的写入!它只说在之后发生的读取,实际上发生在。
之后换句话说,它试图说的是在写入过程中没有发生读取,并且如果还有其他发生在之前的关系导致读取发生在之后写,读取将具有该写入的值。
请参阅JLS部分17.4.4 Synchronization Order,该部分在此上下文中定义了“后续”一词。