どちらの実装も静的である可能性があるため、これが最初の誤解です。このビデオのプレゼンターは、クラス初期化のスレッドセーフを活用する方法を説明しています。
クラスの初期化は本質的にスレッドセーフであり、クラスの初期化でオブジェクトを初期化できる場合は、オブジェクトの作成もスレッドセーフです。
これは、スレッドセーフな静的に初期化されたオブジェクトの例です。
public class MySingletonClass{
private MySingletonClass(){
}
public static MySingletonClass getInstance(){
return IntiailizationOnDemandClassholder.instance;
}
private static class IntiailizationOnDemandClassHolder{
private static final MySingletonClass instance = new MySingletonClass();
}
}
ここで知っておくべき重要なことは、MySingletonClassインスタンス変数は、getInstance()
呼び出されるまで作成または初期化されることはありません。また、クラスの初期化はスレッドセーフであるため、のinstance
変数はIntiailizationOnDemandClassholder
一度安全にロードされ、すべてのスレッドに表示されます。
あなたの編集に答えるのはあなたの他のタイプの実装に依存します。ダブルチェックロックを実行する場合は、インスタンス変数を揮発性にする必要があります。DCLが必要ない場合は、変数へのアクセスを毎回同期する必要があります。次に2つの例を示します。
public class DCLLazySingleton{
private static volatile DCLLazySingleton instance;
public static DCLLazySingleton getInstace(){
if(instance == null){
synchronized(DCLLazySingleton.class){
if(instance == null)
instance=new DCLLazySingleton();
}
}
return instance;
}
と
public class ThreadSafeLazySingleton{
private static ThreadSafeLazySingleton instance;
public static ThreadSafeLazySingleton getInstance(){
synchronized(ThreadSafeLazySingleton.class){
if(instance == null){
instance = new ThreadSafeLazySingleton();
}
return instance;
}
}
最後の例では、インスタンスのすべてのリクエストでロックを取得する必要があります。2番目の例では、アクセスごとにvolatile-readが必要です(安価な場合とそうでない場合がありますが、CPUによって異なります)。
最初の例では、CPUに関係なく、常に1回ロックされます。それだけでなく、各読み取りはスレッドセーフを心配する必要なしに正常になります。私は個人的に私がリストした最初の例が好きです。