Ссылаясь на мой более ранний вопрос о не полностью сконструированных объектах, у меня есть второй вопрос. Как указал Джон Скит, в конце конструктора есть неявный барьер памяти, который гарантирует, что поля final
видны для всех потоков. Но что, если конструктор вызывает другой конструктор; есть ли такой барьер памяти в конце каждого из них или только в конце того, что вызвано в первую очередь? То есть, когда "неправильное" решение:
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
}
И правильным будет версия метода factory:
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
делают это.