引用我的earlier question on incompletely constructed objects ,我有第二个问题。正如 Jon Skeet 指出的那样,在构造函数的末尾有一个隐式内存屏障,它确保 final
字段对所有线程都是可见的。但是,如果构造函数调用另一个构造函数怎么办?他们每个人的末尾都有这样的内存障碍,还是仅在首先被调用的那个的末尾有这样的内存障碍?也就是说,当“错误”的解决方案是:
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
}
正确的应该是工厂方法版本:
public class SafeListener {
private final EventListener listener;
private SafeListener() {
listener = new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
}
}
public static SafeListener newInstance(EventSource source) {
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
}
下面的方法是否也有效?
public class MyListener {
private final EventListener listener;
private MyListener() {
listener = new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
}
}
public MyListener(EventSource source) {
this();
source.register(listener);
}
}
更新: 基本问题是 this()
保证实际调用 上面的私有(private)构造函数(在这种情况下会有预期的屏障,一切都是安全的),或者私有(private)构造函数是否有可能内联到公共(public)构造函数中作为一种优化来保存一个内存屏障(在这种情况下不会有障碍,直到公共(public)构造函数结束)?
this()
的规则是否在某处精确定义?如果不是,那么我认为我们必须假设允许内联链接的构造函数,并且可能某些 JVM 甚至 javac
正在这样做。
最佳答案
我认为它是安全的,因为 java 内存模型指出:
Let o be an object, and c be a constructor for o in which a final field f is written. A freeze action on final field f of o takes place when c exits, either normally or abruptly. Note that if one constructor invokes another constructor, and the invoked constructor sets a final field, the freeze for the final field takes place at the end of the invoked constructor.
关于java - JVM 的隐式内存屏障在链接构造函数时如何表现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2513841/