1

コンストラクターの実行後、参照を返す前にセッターを呼び出すと、安全なパブリケーションになりますか?

public class SafePublication {
    private int i = 0;
    private SafePublication() {
            i = 10;
    }

    // Here we are calling setter are object creation. 
    //Will this change be visible to other threads
   public static SafePublication getInstance() {
           SafePublication pub = new SafePublication();
           pub.setVal(20);
           return pub;
   }

   private void setVal(int x) {
           this.i = x;
   }
}
4

1 に答える 1

3

いいえ、安全ではありません。

setValメソッドは同期されず、i揮発性ではありません。iしたがって、 (経由のsetVal) への更新と、 を読み取る別のスレッドで実行されるコードとの間に同期点はありませんisetValインスタンスを構築するスレッドで呼び出しが発生するという事実が違いを生みます。

肝心なのは、別のスレッドの値を、またはiのいずれかと見なす可能性があるということです。01020


オブジェクトへの参照がまだ返されていない場合、別のスレッドはその値をどのように見ることができますか?

そうではない。問題は、他のスレッドの正しい値を認識しない可能性があることですi

この状況をフィールドが の場合と混同していると思いますfinal。そこでは、JLSフィールドが安全に公開されることを指定します。問題は、この保証が final 以外のフィールドには適用されないことです。JLS 17.5を参照してください。文言は次のとおりです。

「オブジェクトは、コンストラクターが終了したときに完全に初期化されたと見なされます。オブジェクトが完全に初期化された後にのみオブジェクトへの参照を見ることができるスレッドは、そのオブジェクトのfinalフィールドの正しく初期化された値を見ることが保証されています。」

(強調を追加)


むしろ、別のスレッドが i の値を 10 または 20 のいずれかと見なす可能性があると言えます。0 が表示されないことが保証されています。

私の知る限り、 JLS 17.4またはJLS 17.5にはその保証を提供するものは何もありません。保証されている唯一のことは、iデフォルトの初期化が行われる前に の値が表示されないことです。(私が間違っていることを自由に証明してください... JLSへの言及で。)

于 2013-01-02T11:08:55.240 に答える