2011-08-13 20 views
36

シングルトンに関するウィキペディアの記事には、Javaで構造を実装するためのスレッドセーフな方法がいくつか記載されています。私の質問のために、長い初期化プロシージャを持ち、一度に多くのスレッドによってアクセスされるシングルトンを考えてみましょう。スレッドセーフな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に、次の実装のスレッドは初期化時に安全で怠惰なのはなぜですか? 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の例では、どのような一つのスレッドが最初のインスタンスを取得し、別のスレッドがインスタンスを取得し、コンストラクタは、最初のスレッドで終了する前に、それに対してアクションを実行しようとすると?あなたは危険な状態になりますか?

答えて

44

Answer 1:static synchronizedメソッドはクラスオブジェクトをロックとして使用します。つまり、この場合はSingleton.classです。

回答2:Java言語、とりわけ:彼らが最初にアクセスされたときに

  • 負荷クラスは、/クラスへのアクセスが許可される前に、すべての静的初期化子が
  • が完了していることを
  • 保証を使用しました

これらの2つの事実は、内部静的クラスSingletonHolderは、getInstance()メソッドが呼び出されるまでロードされないことを意味します。その時点で、呼び出しを行っているスレッドにアクセス権が与えられる前に、そのクラスの静的インスタンスがクラス読み込みの一部としてインスタンス化されます。

このすべては、私たちがせずに、同期/ロックの任意の必要性を安全な遅延ロード、を持っていることを意味します!

このパターンは、シングルトンに使用するパターンです。です。 MyClass.getInstance()はシングルトンのデファクト業界標準であるため、他のパターンよりも優れているため、シングルトンを使用しているすべての人がシングルトンを扱っていることを知っています(コードは常に明白です)。フードの下での適切な実装。

btw Bill Pugh's articleは、シングルトンパターンを理解する際には、完全性のために読む価値があります。

+0

この記事を読んだ後、静的なフィールドを読み込むときにJavaが「内部」同期を行うということを修正しましたか? – donnyton

+7

_ "このパターンはシングルトンに使用するパターンです。" _ - [有効なJavaの列挙シングルトン](http://stackoverflow.com/questions/427902/java-enum-singleton)についてはどうですか? –

+3

enum singleton IMHOは、このようにきれいではっきりと分かりません。したがって、MyClass.getInstance()は、シングルトンの業界標準です。シングルトンこのパターンには適切なAPI *と適切な実装が実装されています。 – Bohemian

関連する問題