2010-12-19 16 views
10

可能性の重複:
Efficient way to implement singleton pattern in JavaスレッドセーフJavaでシングルトンパターンを効率的に実装する方法は?

私はこのBest Singleton Implementation In Javaを読んでいたが、そのスレッドセーフではありません。ウィキあたりとして

: 1.ダブルヌルチェック:

if(singleton==null) { synchronized(Singleton.class) { // this is needed if two threads are waiting at the monitor at the // time when singleton was getting instantiated if(singleton==null) singleton= new Singleton(); }
}

しかし、バグユーティリティを探すには、この2つのエラーが発生します。 2.静的フィールドの遅延初期化が正しくありません。最良の方法は何

は、それが正しい:

synchronized (Singleton.class) { 
if (singleton== null) { 
singleton= new Singleton(); 
} 
} 
+1

これは上記の質問の複製です。詳細については、その質問を参照してください。しかし、私はその質問にこれらの便利なリンクがあるかどうかは分かりませんので、[Javaのダブルチェック・ロックについて](http://www.ibm.com/developerworks/java/library/j-dcl.html)を参照してください。 [これらの](http://www.ibm.com/developerworks/library/j-jtp02244.html)Java用の[two](http://www.ibm.com/developerworks/library/j-jtp03304/)アップデート5. [Wikipediaのダブルチェックロックに関する記事](http://en.wikipedia.org/wiki/Double-checked_locking)も参照してください。しかし、あなたの質問への実際の答えは、上記の質問を参照してください。 –

答えて

20

シングルトンがちょうど

enum Singleton { 
    INSTANCE 
} 

で遅延読み込みを行うための最も効率的な/最も簡単な方法注:クラスローディングはスレッドセーフであるため、ロックする必要はありません。クラスはデフォルトではfinalであり、コンストラクタはリフレクションによって呼び出すことはできません。 INSTANCEは、INSTANCEまたはクラスが使用されるまで作成されません。クラスが誤って使用されるかもしれないと心配している場合は、内部クラスでシングルトンをラップすることができます。

final class Singleton { 
    private Singleton() { } 
    static class SingletonHolder { 
     static final Singleton INSTANCE = new Singleton(); 
    } 
    public static Singleton getInstance() { 
     return SingletonHolder.INSTANCE; 
    } 
} 

IMHO、あなたはこれをより良い解決策と考えるには非常に妄想的でなければなりません。

+0

2番目のコードでは 'enum'を使用していませんが、' class'を使用していますので、どうやってそれを取るのか混乱します。一度クラスを初期化し、次回にそのオブジェクトを呼び出すように列挙したい。 – manish

+0

@Manishその場合、私が実行するように 'enum'を使用してください最初の例。 –

+0

yahは大丈夫ですが、クラスを一度だけ初期化し、次回にそのインスタンスを 'enum'を使って使用する方法はありますか?それは私の混乱です。私は 'enum Singleton { INSTANCE }'これだけですが、オブジェクトの呼び出しと初期化の方法はありません。 – manish

2

Efficient way to implement singleton pattern in Javaの回答の最初のコードサンプルは、スレッドセーフです。 INSTANCEの作成は、クラスが初めてロードされたときにクラスローダーによって実行されます。それは一度だけ行われ、スレッドセーフな方法である:(What is an efficient way to implement a singleton pattern in Java?からコピー)

public final class Foo { 

    private static final Foo INSTANCE = new Foo(); 

    private Foo() { 
     if (INSTANCE != null) { 
       throw new IllegalStateException("Already instantiated"); 
     } 
    } 

    public static Foo getInstance() { 
     return INSTANCE; 
    } 
} 

問題の第二のサンプルコードが正しく、スレッドセーフであるが、それは呼び出しごとに同期を引き起こしパフォーマンスに影響するgetInstance()に変更してください。

+0

プライベートコンストラクタを保護していないのは、かなり編集的です。リフレクションを使って別のインスタンスを作成しないようにするか、内部クラスがコンストラクタを呼び出すのをやめさせるのでしょうか? –

+0

私は以前の質問から答えを議論していたので、コードをそのままコピーしました。個人的にはif(INSTANCE!= null)チェックも省略します。 –

+0

とそのために私が推測する例外。 ;) –

3

この問題について多くのことが書かれています。はい、単純なダブルチェックロックパターンは安全ではありません。しかし、静的インスタンスをvolatileとして宣言することで安全にすることができます。新しいJava Memory Model仕様では、volatileを扱うときにコンパイラにいくつかのコード並べ替え制限が追加されているため、元々のリスクはなくなっています。インスタンスを作成するときに

はとにかく、私はめったに本当にlazynessのこの種を必要としないので、私は通常、単にクラスのロード時に静的に作成します。

private static MyClass instance = new MyClass(); 

これは短く、明確です。あなたは本当にそれは怠惰なようにしたい場合は別の方法として、あなたはクラスのロード特性を利用し、これを行うことができます:

public class MyClass { 
    private static class MyClassInit { 
     public static final MyClass instance = new MyClass(); 
    } 

    public static MyClass getInstance() { 
     return MyClassInit.instance; 
    } 
... 
} 

ネストされたクラスは、あなたがたgetInstance()を呼び出して最初の時間まではロードされません。

関連する問題