単一スレッドとマルチスレッドでの単一モードの異なる書き方

8893 ワード

単例モードはよく使われるデザインモードの一つですが、今日は異なるシーンでどのように単例を実現するかについてお話しします.
単一のインスタンス・モードの概念は、クラスが1つのインスタンスしかないことを保証し、そのグローバル・アクセス・ポイントにアクセスすることです.主な役割は、Javaアプリケーションでクラスクラスクラスが1つしか存在しないことを保証することです.
単例パターンは一般的に怠け者式と餓漢式に分けられる.
単例のいくつかの書き方:
1.怠け者式(即時ロード方式)
public class Singleton {

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

この書き方は比較的簡単で,クラスロード時にインスタンス化が完了し,スレッド同期の問題を回避した.しかし、このインスタンスを最初から最後まで使用したことがない場合は、メモリの無駄になります.
2.餓漢式(遅延負荷方式)
public class Singleton {

    private static Singleton uniqeInstance = null;
    
    public static Singleton getInstance(){
        if (uniqeInstance == null) {
            uniqeInstance = new Singleton();
        }
        return uniqeInstance;
    }
}

マルチスレッドではこの方式は使用できません.スレッド1がif (uniqeInstance == null)を実行しても、まだ実行が開始されていない場合、スレッド2もこの判断文に合格すると、複数のインスタンスが生成されます.
マルチスレッド操作時の単一モード:
3.メソッドにsynchronizedを付ける(欠点:リソースの消費が多すぎる)
public class Singleton {
	public static  Singleton instance = null;
    public static synchronized Singleton getInstance() {
        if (instance == null ) {
            instance = new Singleton();
        }
        return instance ;
    }
}

4.緊急法によるインスタンスの複数回作成(欠点:メモリ消費)
public class Singleton {
	public static Singleton instance = new Singleton();
    public static Singleton getInstance() {
        if (instance == null ) {
            instance = new Singleton();
        }
        return instance;
    }
}

5.ダブルチェックロック法(推奨使用)
public class Singleton {
	public volatile static Singleton instance = null;
    public static Singleton getInstance() {
        if (instance == null ) {
            synchronized (Singleton.class) {
                if (instance == null ) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

注意:ここで静的変数におけるvolatileキーワードの役割は主に2つある:1).異なるスレッドがこの変数を操作する際の可視性を保証した;2).命令の並べ替えが禁止されているのもこの点であり,複数のスレッドが操作されている場合,どのステップにおいてもinstanceの値が変更されていれば,メモリから直接読み込まれ,複数のインスタンスが作成されることはない.
6.列挙(少ない)
public enum SingletonEnum {
    INSTANCE;
    
    public void whateverMethod() {
        
    }
}

JDK 1.5に追加された列挙によって、一例モードが実現される.マルチスレッド同期の問題を回避するだけでなく、逆シーケンス化による新しいオブジェクトの再作成も防止できます.