不完全に構築されたオブジェクトに関する以前の質問を参照して、2 つ目の質問があります。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()
を実際に呼び出すことが保証されていることです(この場合、意図した場所にバリアがあり、すべてが安全です)、またはプライベート コンストラクターがパブリックコンストラクターにインライン化される可能性はありますか? 1 つのメモリ バリアを節約するための最適化 (この場合、パブリック コンストラクターの最後までバリアはありません)?
のルールはthis()
正確にどこかに定義されていますか? そうでない場合は、チェーンされたコンストラクターのインライン化が許可されていると想定する必要があると思いますjavac
。