Javaの並行処理ノート - シングルトンとデュアル検出

以下からの振替のJava並行処理のメモ-シングルトンとデュアル検出

Singletonパターンは、クラスの唯一のオブジェクトインスタンスは、オブジェクト・スペース・オーバーヘッドを作成するために周波数および時間を削減することができるようにしてもよいです。次のように単一スレッドモードは、一般的なシングルモードコード実施形態です。

class Singleton{
    private static Singleton singleton;    
    private Singleton(){}
    
    public static Singleton getInstance(){
        if(singleton == null){
            singleton = new Singleton();   //1
        }
        return singleton;
    }
}

コンストラクタのプライベート外の世界は、唯一のgetInstance()メソッドを介しての例を得るために、シングルトンクラスのコンストラクタでインスタンス化することはできませんように。これは、オブジェクトを必要なときにのみ作動するインスタンス化される遅延ロードバージョン、です。この方法は、単一のスレッドで正しく動作しますが、何の同期化対策がないため、状況はマルチスレッド環境で表示されます多くのシングルトンオブジェクトにつながります。条件文場合、2つのスレッドAおよびBが存在するかもしれないということである理由は同時に行われる、ブランク判定シングルトンであるので、1つの// CPUタイムスライスを実行する準備ができている、Bも決定シングルトンで空で、次いで、// 1行いますこのとき、オブジェクトのインスタンスを作成し、CPUのタイムスライスを得た後、単一のオブジェクトの実施形態の複数のリードオブジェクトのインスタンスを作成し、// 1行われます。

問題を解決するには、synchronizedキーワードを使用して、簡単です:

class Singleton{
    private static Singleton singleton;    
    private Singleton(){}
    
    public static synchronized Singleton getInstance(){
        if(singleton == null){
            singleton = new Singleton();    //1
        }
        return singleton;
    }
}

これは、マルチスレッドが、効率もたらした同時の問題解決:私たちの目的を、すなわち// 1が1回だけ実行され、インスタンスを1つだけ作成することです、それだけで同期させる必要があり、この場所で、背中のインスタンスを作成します後、シングルトンは、直接非ヌルオブジェクト参照を返すことはなく、すべての空でない同期符号検証ブロックであろう。それだけで1つの//同期で考えられます:

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

これは、複数のスレッドが同時に条件文を実行することです最初の質問、と同じことをもたらすだろうと、それは複数のインスタンスを作成します。問題は、インスタンスの後にスレッドが作成されたとき、シングルトンはもはや空であるが、第2のチェックを行いませんフォローアップスレッドが空でないということではありません。同期コードブロックは再び、いわゆる二重検出をチェックする必要があることは明らかです。

デュアル検出(ダブルチェック):

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

ここでは完璧だった、問題はないようです。JDK1.5前に、この二重の検出メカニズムが問題である。しかし、問題はまだ発生する、いわゆる障害によって書かれた、// 1です。経験のメモリ割り当てが、初期設定は、ヒープ内の一連の動作へのオブジェクト参照を返す場合、オブジェクトが初期化されるとき、一般的に、それは完全なオブジェクトである。このようにして生成されたオブジェクトは、通常使用することができます。しかし、JAVA書き込み障害がオブジェクト参照を返す、逆の順序、すなわちメモリ割り当てをもたらすことができる、シングルトン// 1に対応する初期化シーケンスは、この場合にはヌルではないが、ヒープ上のオブジェクトを指ししかし、オブジェクトがまだ初期化アクションを完了していません。その後のシングルトンスレッドはヌル発見し、予期しない問題が発生したときに直接使用しない場合。

volatileキーワードの重要な役割は、命令の並べ替え、オブジェクト参照を返すことがないことが保証されたメモリの割り当ては、そのような初期化が禁止されているのでJDK1.5た後、あなたは、書かれた順序から生じる問題を解決するための揮発性のキーワードに修正される変数を使用することができますシーケンス、二重の検出が実際に動作するように。もちろん、あなたも二重の検出、および同じ効果を達成するために、非遅延読み込みの方法を使用しないことを選択することができます。

class Singleton{
    private static Singleton singleton = new Singleton();    
    private Singleton(){}
    
    public static Singleton getInstance(){
        return singleton;
    }
}

おすすめ

転載: blog.csdn.net/weixin_43115440/article/details/90480272