83

Head Firstデザイン パターン ブックから、ダブル チェック ロックを使用したシングルトン パターンが以下のように実装されました。

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

が使われている理由がわかりませんvolatilevolatile使用法は二重チェック ロックを使用する目的、つまりパフォーマンスを無効にしません か?

4

7 に答える 7

72

volatileが必要な理由を理解するための優れたリソースは、 JCIPブックから入手できます。ウィキペディアにも、その資料に関する適切な説明があります。

本当の問題は、構築が完了する前にThread Aメモリ空間を割り当てる可能性があることです。その割り当てを見て、それを使用しようとします。の部分的に構築されたバージョンを使用しているため、これは失敗します。instanceinstanceThread BThread Binstance

于 2011-10-21T22:01:04.207 に答える
25

@irreputable で引用されているように、volatile は高価ではありません。コストが高くても、パフォーマンスよりも一貫性を優先する必要があります。

Lazy Singleton のクリーンでエレガントな方法がもう 1 つあります。

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

ソース記事:ウィキペディアの Initialization-on-demand_holder_idiom

ソフトウェア エンジニアリングでは、Initialization on Demand Holder (デザイン パターン) のイディオムは、遅延ロードされたシングルトンです。Java のすべてのバージョンで、このイディオムにより、安全で高度な同時実行遅延初期化が良好なパフォーマンスで実現されます。

クラスには初期化する変数がないためstatic、初期化は簡単に完了します。

その中の静的クラス定義LazyHolderは、JVM が LazyHolder を実行する必要があると判断するまで初期化されません。

静的クラスは、クラス Singleton でLazyHolder静的メソッドが呼び出されたときにのみ実行され、これが最初に発生したときに、JVM がクラスをロードして初期化します。getInstanceLazyHolder

volatileこのソリューションは、特別な言語構造 (または など)を必要とせずにスレッドセーフsynchronizedです。

于 2016-03-19T08:38:52.610 に答える
12

まあ、パフォーマンスのためにダブルチェックされたロックはありません。壊れるパターンです。

感情はさておき、volatileこれがないと、2 番目のスレッドが通過するinstance == nullまでに、最初のスレッドがまだ構築されていない可能性があるためです。実際にオブジェクトを作成するスレッド以外のスレッドに対して、オブジェクトの作成が事前に割り当てられることnew Singleton()を約束する人は誰もいません。instance

volatile次に、読み取りと書き込みの間の事前発生関係を確立し、壊れたパターンを修正します。

パフォーマンスを求める場合は、代わりにホルダーの内部静的クラスを使用してください。

于 2011-10-21T22:01:07.523 に答える
-2

getInstance二重チェック ロックは、マルチスレッド環境でメソッドが呼び出されたときに、シングルトンの別のインスタンスが作成されるのを防ぐための手法です。

注意を払う

  • シングルトン インスタンスは、初期化の前に 2 回チェックされます。
  • 同期化されたクリティカル セクションは、パフォーマンスを向上させるために、シングルトン インスタンスを最初にチェックした後にのみ使用されます。
  • volatileインスタンス メンバーの宣言のキーワード。これにより、コンパイラは、CPU キャッシュではなく、常にメイン メモリから読み書きするように指示されます。変数が事前発生関係をvolatile保証しているため、すべての書き込みはインスタンス変数の読み取りの前に行われます。

短所

  • volatileキーワードが正しく機能する必要があるため、 Java 1.4 以前のバージョンとは互換性がありません。問題は、順不同の書き込みにより、シングルトン コンストラクターが実行される前にインスタンス参照が返される可能性があることです。
  • volatile 変数のキャッシュの拒否によるパフォーマンスの問題。
  • シングルトン インスタンスは、初期化の前に 2 回チェックされます。
  • 非常に冗長で、コードが読みにくくなっています。

シングルトンパターンにはいくつかの実現方法があり、それぞれに長所と短所があります。

  • シングルトンの熱心な読み込み
  • ダブルチェックされたロックシングルトン
  • オンデマンド初期化ホルダーイディオム
  • 列挙ベースのシングルトン

それぞれの詳細な説明は冗長すぎるため、良い記事へのリンクを貼っておきます -シングルトンについて知りたいことすべて

于 2020-01-27T10:28:41.093 に答える