是的,从Java 1.5开始,此代码是正确的。
无论有无波动,原子性都不是问题(对对象引用的写 *** 作是原子的),因此您可以通过任何一种方式将其从关注列表中剔除-
唯一未解决的问题是更改的可见性和排序的“正确性”。
任何对volatile变量的写 *** 作都会建立“先发生”关系(如JSR-133中所指定的新Java内存模型的关键概念),以及随后对同一变量的读取。这意味着读取线程必须对写入线程可见的所有内容具有可见性:也就是说,它必须在写入时查看所有
至少具有 其“当前”值的变量。
我们可以通过查看Java Language
Specification的17.4.5节来详细解释这一点,特别是以下要点:
- “如果x和y是同一线程的动作,并且x在程序顺序中排在y之前,则hb(x,y)”(即,同一线程上的动作不能以与程序顺序不一致的方式重新排序)
- “在以后每次对该字段进行读取之前,都会写入一个易失字段(第8.3.1.4节)。” (这是澄清的文本,解释了易失字段的先写后读是同步点)
- “如果hb(x,y)和hb(y,z),则hb(x,z)”(发生之前的传递)
因此,在您的示例中:
- 由于规则1,对“服务”(a)的写入发生在对“服务就绪”(b)的写入之前
- 由于规则2,对“ serviceReady”(b)的写入发生在读取相同的(c)之前
- 因此,(a)发生在(c)之前(第3条规则)
这意味着在serviceReady为true的情况下,可以保证正确设置“ service”。
您可以使用 几乎完全相同 的示例看到一些好的文章,例如在IBM
DeveloperWorks上看到的-
请参阅“新的保证波动性”:
保证在写入V时A可见的值现在对B可见。
以及由该JSR作者撰写的JSR-133
FAQ中的一个:
因此,如果读者看到v的值为true,则也可以保证看到在它之前发生的对42的写入。在旧的内存模型下,情况并非如此。如果v不易变,则编译器可以对writer中的写入进行重新排序,而读者对x的读取可能会看到0。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)