可以在以下概念Java示例中使用:
public class X implements Runnable {
public volatile Object x = new Object();
@Runnable
public void run() {
for (;;) {
Thread.sleep(1000);
x = new Object();
}
}
}
x
从另一个帖子中被视为null
?
额外奖励:我是否需要声明它是不稳定的(我真的不关心那个值,将来某个时候它将是新指定的值并且永远不会为空)
答案 0 :(得分:4)
技术上,是的,它可以。这是原ConcurrentHashMap's readUnderLock的主要原因。 javadoc甚至解释了如何:
读取锁定条目的值字段。如果值字段似乎为空,则调用。只有当编译器碰巧使用其表分配重新排序HashEntry初始化时才有可能,这在内存模型下是合法的,但是不知道会发生什么。
由于HashEntry的value
是易变的,因此这种类型的重新排序在构造方面是合法的。
故事的道德是所有非最终的初始化都可以与对象构建竞争。
编辑: @Nathan Hughes问了一个有效的问题:
Doug Lea对这个话题有几点评论,整个帖子可以是read here。他回答了评论:@John:在OP的例子中,在运行runnable的线程开始之前,构造是否会发生?看起来这会在场的初始化之后强加一个先发生的障碍。
但问题在于是否必须在volatile存储之后将新C实例分配给其他内存。
回答
很抱歉错误记住为什么我已经基本解决了这个问题: 除非JVM总是预先存储内存(通常不是一个好选项),否则 即使未明确初始化,也必须将volatile字段归零 在构造函数体中,在发布之前使用释放围栏。 即使有些情况下JMM没有 严格要求机械师防止出版物重新排序 在具有volatile字段的类的构造函数中,唯一的好处 JVM的实现选择要么使用非易失性写入 使用尾随释放栅栏,或执行每个易失性写入 完全击剑。无论哪种方式,都没有与出版物重新排序。 不幸的是,程序员不能依赖规范来保证 它,至少在JMM修订之前。
结束时:
程序员并不期望即使最终字段是具体的 出版物安全,易变的领域并非总是如此。
出于各种实现原因,JVM安排这样做 无论如何,易失性领域是安全的,至少在 我们知道的案例。
实际上更新JMM / JLS以强制执行此操作并非易事 (我知道适用的小调整)。但现在是个好时机 考虑对JDK9进行全面修订。
同时,进一步测试是有意义的 并验证JVM是否符合这个可能的未来规范。
答案 1 :(得分:2)
这取决于X
实例的发布方式。
假设x
发布不安全,例如。通过非volatile
字段
private X instance;
...
void someMethod() {
instance = new X();
}
允许访问instance
字段的另一个线程看到引用未初始化的X
对象的引用值(即,其构造函数尚未运行的位置)。在这种情况下,其字段x
的值为null
。
以上示例转换为
temporaryReferenceOnStack = new memory for X // a reference to the instance
temporaryReferenceOnStack.<init> // call constructor
instance = temporaryReferenceOnStack;
但该语言允许以下重新排序
temporaryReferenceOnStack = new memory for X // a reference to the instance
instance = temporaryReferenceOnStack;
temporaryReferenceOnStack.<init> // call constructor
或直接
instance = new memory for X // a reference to the instance
instance.<init> // call constructor
在这种情况下,允许线程在调用构造函数初始化引用的对象之前查看instance
的值。
现在,在当前的JVM中发生这种情况的可能性有多大?呃,我无法想出一个MCVE。
奖金:我是否需要声明它不稳定(我真的不在乎 这个价值,它将来的某个时候就足够了 新分配的值,永远不为空)
安全地发布封闭对象。或者使用您final
的{{1}} AtomicReference
字段。
答案 2 :(得分:1)
没有。 Java内存模型保证您永远不会将x
视为null。 x
必须始终是分配的初始值或后续值。
这实际上适用于任何变量,而不仅仅是volatile
。您所询问的内容被称为“凭空价值”。 C.F. Java Concurrency in Practice ,它在一定程度上讨论了这个概念。
你的问题的另一部分“我是否需要声明x
为volatile:”给定上下文,是的,它应该是volatile
或final.
任何一个提供安全发布对于x
引用的对象。 C.F. Safe Publication.显然,如果x
为final
,则conjugatePresentAr()
以后就无法更改。