关于我之前的问题有关未完全构建的对象, 我有第二个问题。就像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()
是否保证实际调用了上述私有构造函数(如果是这样,那么就会存在预期的屏障,一切都是安全的),还是可能将私有构造函数作为优化内联到公共构造函数中以节省一个内存屏障 (如果是这种情况,则直到公共构造函数结束才会有屏障)?
this()
的规则是否在某个地方被明确定义了? 如果没有,那么我认为我们必须假设允许内联链接构造函数,可能一些JVM或者甚至是javac
正在这样做。