2

シングルトンの二重チェックについて詳しく説明してください。それは長所と短所は何ですか..!! 私はこれを以下のクラスに持っています..どうすれば二重にチェックするシングルトンとしてそれを作ることができますか..

 private DataBaseDAO() { }
        public static synchronized DataBaseDAO getInstance() {
            if (dao == null) {
                dao = new DataBaseDAO();
                }
            return dao;
            }
        }
    }
4

3 に答える 3

3

以下のコードを検討してください

public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {  //1
      if (instance == null)          //2
        instance = new Singleton();  //3
    }
  }
  return instance;
}

ダブルチェック ロックの背後にある理論は、//2 での 2 番目のチェックにより、リストで発生したように 2 つの異なるシングルトン オブジェクトを作成できなくなるというものです。

次の一連のイベントを検討してください。

スレッド 1 が getInstance() メソッドに入ります。

インスタンスが null であるため、スレッド 1 は //1 で同期ブロックに入ります。

スレッド 1 はスレッド 2 によって横取りされます。

スレッド 2 は getInstance() メソッドに入ります。

インスタンスがまだ null であるため、スレッド 2 は //1 でロックを取得しようとします。ただし、スレッド 1 がロックを保持しているため、スレッド 2 は //1 でブロックされます。

スレッド 2 はスレッド 1 によって横取りされます。

スレッド 1 が実行され、インスタンスが //2 でまだ null であるため、Singleton オブジェクトを作成し、その参照をインスタンスに割り当てます。

スレッド 1 は同期ブロックを終了し、getInstance() メソッドからインスタンスを返します。

スレッド 1 はスレッド 2 によって横取りされます。

スレッド 2 は //1 でロックを取得し、インスタンスが null かどうかを確認します。

instance は null ではないため、2 番目の Singleton オブジェクトは作成されず、スレッド 1 によって作成されたオブジェクトが返されます。

ダブルチェック ロックの背後にある理論は完璧です。残念ながら、現実はまったく異なります。ダブルチェック ロックの問題は、シングル プロセッサまたはマルチ プロセッサ マシンで動作する保証がないことです。ダブルチェック ロックの失敗の問題は、JVM の実装バグによるものではなく、現在の Java プラットフォームのメモリ モデルによるものです。メモリ モデルでは、いわゆる「順不同の書き込み」が可能であり、これがこのイディオムが失敗する主な理由です。

于 2012-08-08T16:37:15.157 に答える
3

"Effective Java Second Edition"で説明されているように、良い解決策は "Singleton-as-enum" パターンを使用することです:

public enum DataBaseDAO() {
    INSTANCE;
}

からアクセスしますDataBaseDAO.INSTANCE。これにより、すべての場合において、 のインスタンスが 1 つだけ存在することが保証されますDataBaseDAO

于 2012-08-08T16:42:10.017 に答える
0

コードの実装では、静的メソッド レベルの同期を行っています。DatabaseDAO クラスに他の静的メソッドがある場合、それらのメソッドを使用してメソッドが独立して機能する場合でも、それらは機能しません。これは、ブロック レベルの同期を行うことで回避できます。マルチスレッド アプリケーションでは、これがシングルトン オブジェクトを実装する最も安全な方法の 1 つです。

private DataBaseDAO {
    private static final Object lock = new Object();
    private static DataBaseDAO dao = null;
    private DataBaseDAO() { }
    public static DataBaseDAO getInstance() {
        if (dao == null) {
            synchronize(lock) {
               if (dao == null) {
                   dao = new DataBaseDAO();
                }
            }
        }
        return dao;

    }
}

オブジェクト ロックとしても使用できますDataBaseDAO.class

説明:複数のスレッドgetInstance()が同時にメソッドにアクセスしています。インターリーブされたシナリオでは、2 つ以上のスレッドが最初のチェックに合格できますが、オブジェクトifのロックを取得できるのは 1 つのスレッドだけです。lockロックを取得したスレッドは、インスタンスを作成できます。他のスレッドは、最初のチェックに合格したとしてもif、最初のスレッドがすでにロックを取得している (そして最初のスレッドがロックを解放していない) 場合、ロックを取得できません。

ここで、最初のスレッドがロックを解放したとします。これは、dao オブジェクトもインスタンス化したことを意味します。他のスレッドがスケジュールされている場合、各スレッドはロックを取得しますが、2 番目のifチェックは失敗し、すぐにロックを解放してインスタンス化済みの dao オブジェクトを取得します。

オブジェクトが作成されると、メソッドにアクセスしようとするすべてのスレッドは、最初のスレッド自体が失敗するgetInstance()ため、同期を実行しません。if

于 2012-08-08T16:39:45.710 に答える