2

通常、私は最初の実装を使用します。数日前、私は別のものを見つけました。これら2つの実装の違いを誰かに説明してもらえますか?2番目の実装はスレッドセーフですか?2番目の例で内部クラスを使用する利点は何ですか?

//--1st Impl
public class Singleton{

      private static Singleton _INSTANCE;

      private Singleton() {}
      public static Singleton getInstance(){
          if(_INSTANCE == null){
               synchronized(Singleton.class){
                      if(_INSTANCE == null){
                          _INSTANCE = new Singleton();
                      }
               }
          }
      return _INSTANCE;
      }  
}

//--2nd Impl
public class Singleton {
      private Singleton() {}

      private static class SingletonHolder { 
            private static final Singleton _INSTANCE = new Singleton();
      }

      public static Singleton getInstance() {
            return SingletonHolder._INSTANCE;
      }
}
4

4 に答える 4

7

最初の実装では、いわゆる「ダブルチェックロック」を使用します。これは非常に悪いことです。スレッドセーフに見えますが、実際はそうではありません。

2番目の実装は、実際、スレッドセーフです。

最初の実装が壊れている理由の説明はかなり複雑なので、詳細な説明については、 BrianGoetzのJavaConcurrencyinPracticeのコピーを入手することをお勧めします。短いバージョンでは、コンストラクターが完了する前にコンパイラーが_INSTANCE変数を割り当てることができます。これにより、2番目のスレッドが部分的に構築されたオブジェクトを認識できるようになります。

于 2012-12-01T04:27:27.483 に答える
3

_INSTANCE最初の実装は、が揮発性になっている場合にのみスレッドセーフです。2つ目は、がクラスローダーによってロードされた_INSTANCE後にのみ初期化されるため、スレッドセーフです。SingletonHolder

したがって、内部クラスにしばらくアクセスすると(プログラム全体がロードされるよりもはるかに遅い)、クラスローダーは内部クラスをロードして変数を初期化します。したがって、後でアクセスする場合は、オブジェクトをすぐに利用できます。したがって、このメソッドgetInstance()はスレッドセーフです。

2番目の実装の利点は、同期について心配したり、クラスローダーが実行するようにカウントしたりする必要がないことです。

于 2012-12-01T04:28:20.960 に答える
1

#1は、遅延初期化を保証するように設計されています。ただし、特定の場合、#2は遅延初期化も保証します。_INSTANCEは、Singleton.classがロードされたときにのみ作成され、Singleton.classはgetSingleton()の最初の呼び出しでロードされます。クラスには他のメソッドはありません。ダブルチェックロックは必要ありません。そしてもちろん、#1では_INSTANCEは揮発性である必要があります。

注:ダブルチェックロックが悪いことに同意しません。正しく実装すると、非常に便利な場合があります。

于 2012-12-01T05:10:55.970 に答える
0

最初のコードスニペットは、ダブルチェックされたロックイディオムの例です。これは、以前は非常に人気がありましたが、現在は安全ではないことがわかっているため、使用しないでください。

final2番目のスニペットは、Java言語仕様で定義されているように、クラスのロードとキーワードのセマンティクスの組み合わせを使用して、遅延初期化とスレッドセーフを保証するため、はるかに優れています。

于 2012-12-01T04:30:37.677 に答える