【デザインパターン2】 - シングルトンパターン

シングルトン モード (Singleton): クラスのインスタンスが 1 つだけであることを確認し、それにアクセスするためのグローバル アクセス ポイントを提供します。

シングルトン機能:

  • クラスは 1 つのインスタンスしか持つことができません (コンストラクター プライベート)。
  • このインスタンスを自分で作成する必要があります (インスタンス化ロジックを自分で記述します)。
  • このインスタンスをそれ自体でシステム全体に提供する必要があります (外部でインスタンス化メソッドを提供します)。

クラス図は次のとおりです:
ここに画像の説明を挿入
シングルトン モードは怠け者スタイルとハングリーマン スタイルに分けられます. いくつかの場所では、登録されたシングルトン モードについても言及されています. この 3 つのシングルトン モードについて学びます.

空腹の中華風

public class Person {
    
    
  // 直接创建一个本类的对象
  private static final Person instance = new Person();

  // 构造器私有,外部不能实例化
  private Person() {
    
    
  }

  public static Person getInstance() {
    
    
    return instance;
  }
}

怠惰なスタイル

public class Person {
    
    
  private static Person instance;

  // 构造器私有,外部不能实例化
  private Person() {
    
    
  }
  public static Person getInstance() {
    
    
    // 如果没有实例再去创建
    if (instance == null) {
    
    
      Person person = new Person();
      instance = person;
    }
    return instance;
  }
}

マルチスレッドで遅延スタイルを使用すると、シングルトン モードが破棄されます。

メソッドのロック

public class Person {
    
    
  private static Person instance;

  // 构造器私有,外部不能实例化
  private Person() {
    
    
  }

  // 单例提供给外部的获取方法
  // 1. public static synchronized Person getInstance() 锁太大导致效率低下
  public static synchronized Person getInstance() {
    
    
    // 如果没有实例再去创建
    if (instance == null) {
    
    
      Person person = new Person();
      instance = person;
    }
    return instance;
  }
}

インスタンスを取得するメソッドを直接追加すると、synchronizedマルチスレッド化の問題を解決できますが、この方法では効率が低下します。

ダブルチェックロック + 揮発性

 private volatile static Person instance;
  // 构造器私有,外部不能实例化
  private Person() {
    
    
  }

  // 单例提供给外部的获取方法
  // 1. 双重检查锁 + 内存可见性
  public static synchronized Person getInstance() {
    
    
    // 如果没有实例再去创建
    if (instance == null) {
    
    
      synchronized (Person.class) {
    
    
        if (instance == null) {
    
    
          Person person = new Person();
          instance = person;
        }
      }
    }
    return instance;
  }

ダブルチェック ロックを使用すると、効率が向上します。volatile を使用すると、命令の並べ替えが発生する可能性があります。

シリアル化によってシングルトン パターンが壊れないようにする

シングルトン オブジェクトを作成した後、オブジェクトをシリアル化してディスクに書き込み、次にオブジェクトを使用するときにディスクからオブジェクトを読み取り、逆シリアル化し、メモリ オブジェクトに変換する必要がある場合があります。The deserialized object will re-allocate memory, つまり, recreate it. serialized オブジェクトのターゲットがシングルトン オブジェクトである場合、シングルトン パターンの本来の意図に違反することになり、シングルトンを破棄することと同じになります。

解決策:クラスのreadResolve()メソッドをオーバーライドするだけです
ここに画像の説明を挿入

リフレクションがシングルトン パターンを壊さないようにする

空腹の中華風

Hungry Chinese シングルトン パターンの場合、インスタンスがコンストラクター内にあるかどうかを直接判断する場合null、コードは次のようになります。

public class Person {
    
    
  private volatile static Person instance = new Person();

  // 构造器私有,外部不能实例化
  private Person() {
    
    
    if (instance != null) {
    
    
      throw new RuntimeException("单例不允许多实例");
    }
  }

  public static Person getInstance() {
    
    
    return instance;
  }

怠惰なスタイル

反射破壊を防ぐフラグを追加

public class Person {
    
    
  private volatile static Person instance;
  private static boolean flag = false;

  // 构造器私有,外部不能实例化
  private Person() {
    
    
    synchronized (Person.class) {
    
    
      if (!flag) {
    
    
        flag = true;
      } else {
    
    
        throw new RuntimeException("单例不允许多实例");
      }
    }
  }


  public static synchronized Person getInstance() {
    
    
    // 如果没有实例再去创建
    if (instance == null) {
    
    
      synchronized (Person.class) {
    
    
        if (instance == null) {
    
    
          Person person = new Person();
          instance = person;
        }
      }
    }
    return instance;
  }
}

実際、フラグ ビットはリフレクションがシングルトン モードを破壊するのを防ぐことはできず、シングルトン モードは列挙型クラスを介して実装され、リフレクションが壊れるのを防ぐことができます。

おすすめ

転載: blog.csdn.net/qq_60361946/article/details/128581604