は、私がthisを見つけた:この静的な最終変数は、単一スレッドセーフではなぜですか?このサイトを読ん
クラスが実際に使用されたときに[ザ・]ライン
private static final Foo INSTANCE = new Foo();
のみが実行され、これは怠惰なインスタンス化の世話をする、そしてそれは、スレッドセーフであることが保証されています。
これはスレッドセーフであることが保証されるのはなぜですか?このフィールドはの最終なので、それとも何か他の理由で?
は、私がthisを見つけた:この静的な最終変数は、単一スレッドセーフではなぜですか?このサイトを読ん
クラスが実際に使用されたときに[ザ・]ライン
private static final Foo INSTANCE = new Foo();
のみが実行され、これは怠惰なインスタンス化の世話をする、そしてそれは、スレッドセーフであることが保証されています。
これはスレッドセーフであることが保証されるのはなぜですか?このフィールドはの最終なので、それとも何か他の理由で?
最終的なので、はい。最終変数には特別なスレッドセーフティセマンティクスがあります。他のスレッドは、少なくともコンストラクターが終了したときの状態で最終フィールドを確認することが保証されています。
これはJLS 17.5ですが、言語は少し濃くなっています。これらのセマンティクスはJava 1.5で、特にJSR-133によって導入されました。 JSR-133の非スペックの議論とそのさまざまな意味については、このページを参照してください。
コンストラクタの後でインスタンスを変更すると、でなく、がスレッドセーフである必要があります。その場合、起こりうるエッジを確実にするために、通常のスレッドの安全上の注意を守る必要があります。
1つのスレッドだけがクラスの初期化を行うという事実は、ではなく、ここではです。クラスが1つのスレッドでのみ初期化されていることは事実ですが、そのスレッド間で特定の発生前エッジが確立されているとは思われません(他のスレッドは再初期化を行わないクラス)。したがって、final
キーワードがなければ、別のスレッドはオブジェクトの部分的に構築されたインスタンスを見ることができます。 JMMが定義する特定の先行エッジはJLS 17.4.5にあり、クラスの初期化はそこにリストされていません。
どのクラスの静的初期化ブロックもシングルスレッドであることが保証されています。単純なシングルトンは、これも安全でクラスがレイジー初期化スレッドです列挙型に
enum Singleton {
INSTANCE;
}
を使用することです。
JLS? – paislee
@paislee:私はJVMSでもっと家にいるので、[参考まで](http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc)を提供することができます。 html#24237)。この手順に従うと、クラスの初期化は単一のスレッド(クラスローダーごと)でのみ行うことができます。静的初期化子は、手順8で呼び出されます。 – musiKk
JVMSは、JLSよりも様々な意味でより厳密なセマンティクスを提供します。したがって、一般的な言語の正確さのための大きなソースではありません。 JLSは[JLS 12.4](http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4)のクラスの初期化を定義しており、12.4.2ではその手順を詳しく説明しています。 – yshavit
JVMは静的イニシャライザが単一のスレッドで実行されることを保証するため、スレッドセーフであることが保証されています。
Fooのインスタンスが内部的にスレッドセーフであることを意味するわけではありません。つまり、Fooのコンストラクタがこの特定のコードパスを介して1つのスレッドで1回だけ呼び出されることが保証されていることを意味します。
クラスのコンストラクタおよび静的/インスタンス初期化子をアトミックに実行されることが保証とprivate static final FOO INSTANCE = new FOO;
を
private static final FOO INSTANCE;
static{
INSTANCE = new FOO();
}
と同等であるので、この場合は、上記のカテゴリに入るされています。
はい、ありがとうございます。グレート答え – MyTitle
私は、最終的なよりも重要な理由は、クラスの初期化(静的な初期化)が同期され、スレッドセーフでなければならないと考えています。それは、同期を使用して、先発順序を確立する。詳細は、12.4.2(http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4.2)を参照してください。 – sjlee
@sjlee初期化ではロックが必要ですが、スレッドAがMyClassを初期化し、スレッドBが5分後にMyClassを使用すると、スレッドBはMyClassを初期化しようとしません(すでに初期化されているため)。これは、MyClass.classにロックを取得しないことを意味します。つまり、スレッドAのアクションとスレッドBの間には何も起こりません。すべてのスレッドが使用するたびに 'MyThread.class'をロックした場合、他の先起こりの関係を確立する必要はありません。 – yshavit