単純で単純でない単例モード、単例モードの改善


Singleton(Singleton)はほとんど開発者たちの最初の設計モデルである.
Singleton V 1バージョン
// Version 1
public class Single1 {
    private static Single1 instance;
    public static Single1 getInstance() {
        if (instance == null) {
            instance = new Single1();
        }
        return instance;
    }
}

コンストラクタをプライベートに変更することで、外部のクラス呼び出しを防止できます.
// Version 1.1
public class Single1 {
    private static Single1 instance;
    private Single1() {}
    public static Single1 getInstance() {
        if (instance == null) {
            instance = new Single1();
        }
        return instance;
    }
}

instanceを取得するたびに判断し、instanceが空の場合はnewが1つ出てきます.そうしないと、既存のinstanceに戻ります.
この書き方は多くの場合問題ありません.問題は、マルチスレッドが動作する場合、if(instance==null)まで複数のスレッドが同時に実行され、nullと判断されると、2つのスレッドがそれぞれ1つのインスタンスを作成することであり、これは単一の例ではないということです.
Singleton  V 2バージョンsynchronized
// Version 2 
public class Single2 {
    private static Single2 instance;
    private Single2() {}
    public static synchronized Single2 getInstance() {
        if (instance == null) {
            instance = new Single2();
        }
        return instance;
    }
}

synchronizedキーワードを付けるとgetInstanceメソッドがロックされます.
2つのスレッド(T 1,T 2)が同時にこの方法を実行すると、1つのスレッドT 1が同期ロックを取得して実行を継続し、もう1つのスレッドT 2が待機する必要があり、T 1がgetInstanceを実行した後(null判定、オブジェクト作成、戻り値の取得が完了した後)、T 2スレッドが実行される.したがって、このコードはVersion 1では、マルチスレッドによって複数のインスタンスが発生する可能性があることを回避します.ただし、gitInstanceメソッドにロックをかけると、複数のインスタンスの問題が発生する可能性は回避されますが、T 1以外のすべてのスレッドを強制的に待機させ、実際にはプログラムの実行効率に悪影響を及ぼすという問題もあります.
Singleton  V 3バージョンダブルチェック(Double-Check)バージョン
Version 2コードのVersion 1 dコードに対する効率の問題は,実際には1%確率の問題を解決するために100%出現するシールドを用いた.100%出現するシールドを1%の確率で出現させ、複数のインスタンスが出現する可能性のある場所にのみ出現させる最適化の考え方がある.
——そんな方法はありませんか?もちろんありますが、改良されたコードVsersion 3は以下の通りです.
// Version 3 
public class Single3 {
    private static Single3 instance;
    private Single3() {}
    public static Single3 getInstance() {
        if (instance == null) {
            synchronized (Single3.class) {
                if (instance == null) {
                    instance = new Single3();
                }
            }
        }
        return instance;
    }
}

このバージョンのコードは少し複雑に見えますが、if(instance==null)の判断が2回あることに注意してください.これを『ダブルチェックDouble-Check』と言います.
  • 最初のif(instance==null)は、Version 2の効率の問題を解決するために、instanceがnullの場合にのみsynchronizedのコードセグメントに入る--確率が大幅に減少した.
  • の2番目のif(instance==null)は、Version 2と同様に、複数のインスタンスが発生する可能性を防止するためである.

  • --このコードはもう完璧に見えます.でも
    高同時性では,コードの原子性と命令再配列機構により,小さな確率でエラーが報告される.
    Singleton  V 4版volatile バージョン#バージョン#
    // Version 4 
    
    public class Single4 {
    
        private static volatile Single4 instance;
    
        private Single4() {}
    
        public static Single4 getInstance() {
    
            if (instance == null) {
    
                synchronized (Single4.class) {
    
                    if (instance == null) {
    
                        instance = new Single4();
    
                    }
    
                }
    
            }
    
            return instance;
    
        }
    
    }