Java:通过_happens-before_关系在构造函数中“泄漏”此引用是否安全?
Goetz 的“Java 并发实践”的第 3.2.1 节包含以下规则:
在施工期间不允许引用逃逸
this
我理解,一般来说,允许转义会导致其他线程看到对象的不完整构造版本,并违反字段的初始化安全保证(例如,在这里讨论)this
final
)
但是,是否有可能安全地泄漏它
?特别是,如果您在泄漏之前建立了先发生
关系?
例如,官方执行器Javadoc说
在将对象提交到 happen 之前(在其执行开始之前,可能在另一个线程中)在线程中的操作
Runnable
Executor
我对Java内存模型的天真理解是,像下面这样的东西应该是安全的,即使它在构造函数结束之前泄漏:this
public final class Foo {
private final String str1;
private String str2;
public Foo(Executor ex) {
str1 = "I'm final";
str2 = "I'm not";
ex.execute(new Runnable() {
// Oops: Leakage!
public void run() { System.out.println(str1 + str2);}
});
}
}
也就是说,即使我们已经泄漏到一个潜在的恶意,在泄漏之前和发生之前,对象是完全构造的,即使它还没有按照JLS 17.5“完全初始化”。this
Executor
str1
str2
请注意,我还要求类为 ,因为任何子类的字段都将在泄漏后初始化。final
我在这里错过了什么吗?这真的能保证表现良好吗?在我看来,这就像是“搭载同步”(16.1.4)的一个合法例子,总的来说,我非常希望能指出任何涉及这些问题的额外资源。
编辑:我知道,正如@jtahlborn所指出的,我可以通过使用公共静态工厂来避免这个问题。我正在寻找问题的答案,以巩固我对Java内存模型的理解。
编辑#2:这个答案暗示了我试图得到的东西。也就是说,遵循其中引用的JLS规则足以保证所有字段的可见性。但这是必要的,还是我们可以利用其他先发生机制来确保我们自己的可见性保证?final