Goetz 的 Java Concurrency in Practice ,第 41 页,提到 this
引用如何在构造过程中转义。一个“不要这样做”的例子:
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
}
这里 this
通过 doSomething(e)
引用封闭的 ThisEscape
实例这一事实“转义”。这种情况可以通过使用静态工厂方法(首先构造普通对象,然后注册监听器)而不是公共(public)构造函数(完成所有工作)来解决。本书继续:
Publishing an object from within its constructor can publish an incompletely constructed object. This is true even if the publication is the last statement in the constructor. If the
this
reference escapes during construction, the object is considered not properly constructed.
我不太明白。如果发布是构造函数中的最后一条语句,那么在此之前不是所有的构造工作都完成了吗?那个时候this
怎么会失效呢?显然在那之后发生了一些巫术,但是什么?
最佳答案
相对于 final 字段,构造函数的末尾在并发方面是一个特殊的地方。来自 section 17.5 Java 语言规范:
An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.
The usage model for final fields is a simple one. Set the final fields for an object in that object's constructor. Do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are.
换句话说,如果在另一个线程中检查对象,您的监听器最终可能会看到具有默认值的最终字段。如果在构造函数完成后发生监听器注册,则不会发生这种情况。
就正在发生的事情而言,我怀疑在构造函数的最后有一个隐式内存屏障,确保所有线程“看到”新数据;如果没有应用内存屏障,可能会出现问题。
关于java - 什么是 "incompletely constructed object"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2513597/