挥发性出版物的保证深度如何?

挥发性出版物的保证深度如何?,第1张

挥发性出版物的保证深度如何?

在当前的Java内存模型领域中,

volatile
不等于
final
。换句话说,您不能将替换
final
volatile
,并认为安全构造保证是相同的。值得注意的是,这在理论上可能会发生:

public class M {  volatile int x;  M(int v) { this.x = v; }  int x() { return x; }}// thread 1m = new M(42);// thread 2M lm;while ((lm = m) == null); // wait for itprint(lm.x()); // allowed to print "0"

因此,

volatile
在构造函数中编写字段并不安全。

直觉:

m
上面的例子中有一场竞赛。创造 场地 并不能消除种族
M.x

volatile
,只有制造
m
自己
volatile
会有所帮助。换句话说,
volatile
该示例中的修饰符在 错误的位置
可用。在安全发布中,您必须具有“写入->易失性写入->易失性读取,可观察到易失性写入->读取(现在先观察易失性写入之前的写入)”,而必须具有“易失性写入->写入->读取-

易失性读取(不遵循易失性写入)”。

琐事1:
此属性表示我们可以

volatile
在构造函数中更加积极地进行优化。这证实了
this
可以放松未观察到的易失性存储的直觉(实际上,直到具有非转义完成的构造函数才观察到)。

琐事2:
这也意味着您不能安全地初始化

volatile
变量。在上面的示例中替换
M
AtomicInteger
,您将具有独特的现实生活行为!调用
newAtomicInteger(42)
一个线程,不安全地发布该实例,然后
get()
在另一个线程中执行-
您是否保证遵守
42
?如前所述,JMM说“不”。Java内存模型的最新修订版努力确保所有初始化的安全构造,以捕获这种情况。许多重要的非x86端口已经加强了它的安全性。

Trivia 3: Doug Lea:“

final
vs
volatile
问题导致在java.util.concurrent中进行了一些曲折的构造,以允许在自然不存在的情况下将0用作基本/默认值。该规则很糟糕,应该更改。”

也就是说,可以使示例更加狡猾:

public class C {  int v;  C(int v) { this.x = v; }  int x() { return x; }    }public class M {  volatile C c;  M(int v) { this.c = new C(v); }  int x() {     while (c == null); // wait!    return c.x();  }}// thread 1m = new M(42);// thread 2M lm;while ((lm = m) == null); // wait for itprint(lm.x()); // always prints "42"

如果 volatile读取观察到volatile写入构造函数中写入的值 之后
存在一个传递性直读

volatile
字段,则通常的安全发布规则开始生效。 __



欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5623241.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-15
下一篇2022-12-15

发表评论

登录后才能评论

评论列表(0条)

    保存