1

「最終」に関連する保証についてJMMに言及したとき、私は最近混乱しました。JMM からの抜粋と例を次に示します。

図 4 は、最終フィールドが通常のフィールドとどのように比較されるかを示す例を示しています。クラス FinalFieldExample には、最終的な int フィールド x と非最終的な int フィールド y があります。1 つのスレッドが writer() メソッドを実行し、別のスレッドが reader() メソッドを実行する場合があります。オブジェクトのコンストラクターが終了した後に writer() が f を書き込むため、reader() は fx の適切に初期化された値を確認することが保証されます。つまり、値 3 を読み取ります。ただし、fy は最終的なものではありません。したがって、reader() メソッドが値 4 を表示することは保証されていません。

class FinalFieldExample {
    final int x;
    int y;
    static FinalFieldExample f;

    public FinalFieldExample() {
      x = 3;
      y = 4;
    }

    static void writer() {
      f = new FinalFieldExample();
    }

    static void reader() {
      if (f != null) {
        int i = f.x; // guaranteed to see 3
        int j = f.y; // could see 0
      }
    }
}

私の混乱は、オブジェクト「Obj」が最終フィールドと非最終フィールドを持ち、完全に初期化され、スレッド「T」によって参照されていることです.Tは最終フィールドの正しい値のみを参照しますか? 構築後に変更されない非最終フィールドはどうなりますか。構築スレッド 'T' の後にそれらが変更された場合、新しい値が表示されない可能性があることを理解しています (フィールドが volatile でない限り)。しかし、フィールドが非最終的かつ非揮発性であり、構築後に変更されていない場合はどうなりますか?

JVM は 'final' に関連付けられた保証をどのように実装しますか? たとえば、volatile にはメモリバリアがあります。

4

3 に答える 3

6

これは、この回答で対処されています。

これはオブジェクトの安全な公開ですか?

引用するには:

この問題は、命令の最適化と並べ替えに関係しています。同期せずに構築されたオブジェクトを使用している 2 つのスレッドがある場合、コンパイラが効率のために命令の順序を変更し、オブジェクトにメモリ空間を割り当て、その参照を item フィールドに格納してから、コンストラクタとフィールドの初期化。または、メモリ同期を並べ替えて、他のスレッドがそのように認識できるようにすることもできます。

フィールドを最終としてマークすると、コンストラクターが完了する前に、コンパイラーがそのフィールドの初期化を完了するように強制されます。非 final フィールドには、そのような保証はありません。

これはJava 言語定義 (17.4)の一部です。finalフィールドの詳細はJLS (17.5)にもあります。

より具体的には、このwriter()メソッドは のインスタンスを構築し、他のスレッドが使用できるようにフィールドにFinalFieldExample格納します。static命令の並べ替えのため、yフィールドがまだ初期化されていない可能性があります。同じスレッドが を呼び出した場合、reader()それはyasと見なされます4が、他のスレッドはそれを asと見なす可能性0がありますf y

このコードを正しくするには、同じようにする必要がありfますvolatile

于 2013-11-13T23:50:32.373 に答える
3

JVM は 'final' に関連付けられた保証をどのように実装しますか? たとえば、volatile にはメモリバリアがあります。

フィールドのセマンティクスを尊重するためにfinal、一部の並べ替えは実​​行できず、(一部のプロセッサでは) いくつかのメモリ バリアが必要になる場合があります。http://g.oswego.edu/dl/jmm/cookbook.htmlを参照

これfinalは、無料のランチではないことを意味します。finalどこでも使用する前に、それを考慮してください。(ジョシュアの本にあるからといって、それが正しいとは限りません)

于 2013-11-14T02:27:32.340 に答える
1

私の混乱は、オブジェクト「Obj」が最終フィールドと非最終フィールドを持ち、完全に初期化され、スレッド「T」によって参照されていることです.Tは最終フィールドの正しい値のみを参照しますか?

すべてのスレッドで、フィールドの正しい値が表示されることが保証さfinalれます。これは、非 final フィールドについては何も言いません。

構築後に変更されない非最終フィールドはどうなりますか。

修飾子は特定のfinalフィールドにのみ適用されます。他の非最終フィールドで「幸運」になるかもしれませんが、保証はとしてマークされたフィールドにのみfinal適用されます。

非最終フィールドがコンストラクターで設定され、後で変更されないという事実は関係ありません。

于 2013-11-13T23:47:25.090 に答える