単項パターンとは
シングルトンパターンは、シングルトンオブジェクトのクラスは1つのインスタンスしか存在できないという事実によって定義される、よく使われるソフトウェアデザインパターンです。
多くの場合、システム全体のグローバルオブジェクトは1つだけで、システム全体の振る舞いを調整するのに役立ちます。例えば、サーバープログラムでは、サーバーのコンフィギュレーション情報はファイルに保存され、シングルトンオブジェクトによって読み込まれ、サービスプロセス内の他のオブジェクトはこのシングルトンオブジェクトを通してコンフィギュレーション情報を取得します。このアプローチにより、複雑な環境における設定管理が簡素化されます。
シングル・インスタンスは主に2つのステップで実装されます:
- クラスのコンストラクタ・メソッドを private として定義して、他のコードがクラスのコンストラクタ・メソッドを呼び出してクラスのオブジェクトをインスタンス化できないようにします;
- 呼び出されたときに、NULL ではない参照を保持している場合はそのクラスへの参照を返し、NULL の参照を保持している場合はそのクラスのインスタンスを作成し、そのインスタンスへの参照をクラスが保持している参照に代入します。
第二に、シングルインスタンスパターンの実装
ハングリー・マン・スタイル
public class Singleton {
//静的オブジェクトを作成する
private static Singleton singleton = new Singleton();
//プライベート・コンストラクタ
private Singleton(){}
//共有アクセス・インターフェース
public static Singleton getInstance() {
return singleton;
}
}
テスト:出力:設計原則:
クラスはオンデマンドで一度だけロードされることが知られています。したがって、上記の単一インスタンスクラスがロードされるとき、オブジェクトをインスタンス化し、システムによって使用されるためにそれ自身への参照を渡します。
- 長所: よりシンプルな書き方で、クラスがロードされたときにインスタンス化が行われます。スレッド同期の問題を回避できます。
- 短所:インスタンス化はクラスがロードされたときに行われるため、遅延ロードの効果がありません。インスタンスが最初から最後まで使用されない場合、メモリが無駄になります。
怠け者
public class LayzSingleton {
private static LayzSingleton instance = null;
private LayzSingleton(){}
public static LayzSingleton getInstance() {
if (instance == null) {
instance = new LayzSingleton();
}
return instance;
}
}
テスト:出力:設計原則:遅延シングルトンからわかるように、シングルトンインスタンスは遅延ロードされます。
- 長所:遅延ロードによる高速起動、リソース使用量の少なさ
- 短所:スレッドが安全でない
スレッドセーフなスラッカースタイル
public class SynchronizedSingleton {
private static SynchronizedSingleton instance = null;
private SynchronizedSingleton(){}
private synchronized SynchronizedSingleton getInstance() {
if (instance == null) {
instance = new SynchronizedSingleton();
}
return instance;
}
}
設計原理:レイジーマンタイプは、ハングリーマンタイプのリソースの無駄を省くが、それはスレッドセーフの問題をもたらします、もし(インスタンス== NULL)のコードでは、この最後まで実行されているスレッドがまだ終了していない場合、他のスレッドもここで実行され、2つのスレッドが単項オブジェクトの作成に実行され続けるので、単項オブジェクトは1つ以上です。解決策は、getInstance() メソッドに同期ロックを追加して、スレッドセーフにすることです。
- 利点: 遅延ロードによる高速起動、小さなリソースフットプリント、スレッドセーフ
- 欠点:synchronizedは排他的かつ排他的なロックであり、同時実行性能が低い。作成に成功しても、インスタンスの取得は直列化された操作のままです。
ダブルロック・スラッカー・スタイル
public class DoubleCheckSingleton {
private volatile static DoubleCheckSingleton instance = null;
private DoubleCheckSingleton(){}
public static DoubleCheckSingleton getInstance() {
//まずインスタンスが存在するかどうかをチェックし、存在しない場合は次の同期ブロックに入る前にチェックする。
if (instance == null) {
//同期コードブロック、スレッドセーフなインスタンス生成
synchronized (DoubleCheckSingleton.class) {
//インスタンスが存在するかどうかを再度チェックし、存在しない場合にのみインスタンスを生成する。
if (instance == null) {
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
設計原理:揮発性キーワードの使用は、変数の可視性を確保するために、ユナリオブジェクトは、値が変更された場合、他のスレッドがすぐに見える、ダーティリーリーディングの現象を避けるために、同期同期コードブロックの使用は、スレッドのきめ細かな制御は、ユナリオブジェクトを作成するため、より安全で、同時に、パフォーマンスが同期メソッドよりも優れています。利点:遅延ロード、スレッドセーフ。
注意:インスタンスは、完全な初期化を保証する volatile キーワードで変更する必要があります。
静的インナークラスのアプローチ
public class StaticClassSingleton {
/**
* クラス・レベルの内部クラス、つまり静的メンバ・ベースの内部クラス、この内部クラスのインスタンスと外部クラスのインスタンス
* バインディング関係はなく、呼び出されたときにのみロードされる。
*/
private static class SingletonHolder{
private static StaticClassSingleton instance = new StaticClassSingleton();
}
private StaticClassSingleton(){}
public static StaticClassSingleton getInstance() {
return SingletonHolder.instance;
}
}
長所:遅延ロード、スレッドセーフ 短所:シリアライズとデシリアライズの存在は、2つの異なるインスタンスの生成につながります。
列挙の実装
public enum EnumSingleton {
//
INSTANCE;
}
テスト: 出力: メリット
- 自由な直列化;
- インスタンスは1つだけであることが保証されています;
- スレッドセーフ
まとめ
シングルトンパターンの概念
- 全方位で共有できる、唯一無二の存在
- コンストラクタは公開されておらず、コンストラクタ自身が責任を負います;
- ハングリーマンスタイル:最初は良いアプリケーションですが、リソースを少し浪費しますが、スレッドセーフです。
- 遅延ロード:遅延ロード、使用時のみロード、スレッドセーフではありません。スレッドセーフを確保する方法:
- synchronized getInstance()
- ロックのダブルチェック。
- ホルダーモード:静的内部クラスへの変更、JVMによってスレッドセーフが保証されます。
- 列挙の実装:自由な直列化、1つのインスタンスのみを保証、スレッドセーフ