シングルトンに関するウィキペディアの記事では、Javaで構造を実装するいくつかのスレッドセーフな方法について言及しています。私の質問では、長い初期化手順があり、一度に多くのスレッドがアクセスするシングルトンについて考えてみましょう。
まず、この言及されていないメソッドはスレッドセーフであり、その場合、何に同期しますか?
_public class Singleton {
private Singleton instance;
private Singleton() {
//lots of initialization code
}
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
_
次に、次の実装はなぜスレッドセーフで初期化が面倒なのですか? 2つのスレッドが同時にgetInstance()
メソッドに入った場合、正確にはどうなりますか?
_public class Singleton {
private Singleton() {
//lots of initialization code
}
private static class SingletonHolder {
public static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
_
最後に、2番目の例では、あるスレッドが最初にインスタンスを取得し、別のスレッドがインスタンスを取得して、コンストラクターが最初のスレッドで完了する前にインスタンスでアクションを実行しようとするとどうなるでしょうか。では、危険な状態に入ることができますか?
回答1:_static synchronized
_メソッドは、クラスオブジェクトをロックとして使用します。つまり、この場合は_Singleton.class
_です。
回答2:Java言語、とりわけ:
これらの2つの事実は、getInstance()メソッドが呼び出されるまで、内部静的クラスSingletonHolder
がロードされないことを意味します。その時点で、呼び出しを行うスレッドにアクセスが許可される前に、そのクラスの静的インスタンスがクラスのロードの一部としてインスタンス化されます。
つまり、安全な遅延読み込みおよびがあり、同期/ロックにanyする必要はありません!
このパターンは、シングルトンに使用するtheパターンです。 MyClass.getInstance()
はシングルトンの事実上の業界標準であるため、他のパターンに勝っています。これを使用するすべての人は、シングルトンを処理していることを自動的に認識します(コードを使用すると、常に明白であることが望ましいです)。適切なAPIおよび内部での適切な実装。
btw Bill Pughの記事 は、シングルトンパターンを理解する上で、完全に読む価値があります。