設計モードシリーズの単例モード
6867 ワード
単一モード
Singleton Pattern(Singleton Pattern)はJavaの中で最も簡単な設計モードの一つである.このタイプの設計モードは、オブジェクトを作成するための最適な方法を提供する作成モードに属します.
このモードは、独自のオブジェクトを作成し、単一のオブジェクトのみが作成されることを保証する単一のクラスに関連します.このクラスは、クラスのオブジェクトをインスタンス化する必要がなく、直接アクセスできる独自のオブジェクトにアクセスする方法を提供します.
注意:1、単一のクラスには1つのインスタンスしかありません. 2、単一のインスタンスクラスは、独自の一意のインスタンスを独自に作成する必要があります. 3、単一のクラスは、このインスタンスを他のすべてのオブジェクトに提供する必要があります.
紹介する
意図:クラスにインスタンスが1つしかないことを保証し、グローバル・アクセス・ポイントを提供します.
主な解決:グローバルに使用されるクラスが頻繁に作成され、破棄されます.
≪いつ使用|Use|emdw≫:インスタンスの数を制御し、システム・リソースを節約したい場合.
どのように解決するか:システムにこの単例があるかどうかを判断し、ある場合は戻り、ない場合は作成します.
キーコード:コンストラクション関数はプライベートです.
応用例:1、1クラスに1人の担任しかいない.2、Windowsはマルチプロセスマルチスレッドであり、1つのファイルを操作する場合、複数のプロセスまたはスレッドが同時に1つのファイルを操作する現象は避けられないため、すべてのファイルの処理は唯一のインスタンスで行わなければならない.3、一部のデバイスマネージャは、1つのコンピュータに2台のプリンタがあり、出力時に2台のプリンタで同じファイルを印刷できないように処理するなど、単一のモードとして設計されることが多い.
利点:1、メモリにインスタンスが1つしかないため、メモリのオーバーヘッドが削減され、特に頻繁にインスタンスの作成と破棄(管理学院のトップページページキャッシュなど)が行われます.2、資源の多重占有(例えばファイルを書く操作)を避ける.
欠点:インタフェースがなくて、継承することができなくて、単一の職責の原則と衝突して、1つのクラスは内部の論理だけに関心を持つべきで、外がどのように実例化することに関心を持たない.
使用シーン:1、一意のシリアル番号を生産する必要があります.2、WEBのカウンターは、リフレッシュするたびにデータベースに一度加算することなく、一例で先にキャッシュします.3、作成したオブジェクトは、I/Oとデータベースの接続など、消費するリソースが多すぎる.
注意:getInstance()メソッドでは、同期ロックsynchronized(Singleton.class)を使用して、マルチスレッドが同時にinstanceが複数回インスタンス化されることを防止する必要があります.
インプリメンテーション
SingleObjectクラスを作成します.SingleObjectクラスには、そのプライベート構造関数とそれ自体の静的インスタンスがあります.
SingleObjectクラスは、外部から静的インスタンスを取得するための静的メソッドを提供します.SingletonPatternDemo,我々のプレゼンテーションクラスはSingleObjectクラスを使用してSingleObjectオブジェクトを取得する.
ステップ1
Singletonクラスを作成します.
SingleObject.java
ステップ2
singletonクラスから一意のオブジェクトを取得します.
SingletonPatternDemo.java
手順3
出力を確認します.
単例モードのいくつかの実現方式
単一のモードの実装には、以下に示すように、いくつかの方法があります.
1、怠け者式、スレッドが安全ではない
Lazy初期化の有無:Yes
マルチスレッドが安全かどうか:いいえ
実現難易度:易
説明:この方式は最も基本的な実現方式であり、この実現の最大の問題はマルチスレッドをサポートしないことである.synchronizedはロックされていないため、厳密には単一のモードではありません.この方式lazy loadingは明らかで,スレッドの安全を要求せず,マルチスレッドでは正常に動作しない.
コードの例:
次に説明する実装のいくつかは、マルチスレッドをサポートしていますが、パフォーマンスに違いがあります.
2、怠け者式、スレッド安全
Lazy初期化の有無:Yes
マルチスレッドが安全かどうか:はい
実現難易度:易
説明:この方式はlazy loadingが優れており、マルチスレッドでよく動作することができるが、効率が低く、99%の場合同期を必要としない.利点:メモリの無駄を回避するために、最初の呼び出しで初期化されます.欠点:synchronizedをロックする必要がありますが、ロックは効率に影響します.getInstance()のパフォーマンスはアプリケーションにとって重要ではありません(この方法はあまり頻繁に使用されません).
コードの例:
3、餓漢式
Lazy初期化の有無:No
マルチスレッドが安全かどうか:はい
実現難易度:易
説明:この方法は一般的ですが、ゴミオブジェクトが発生しやすいです.利点:ロックが付いていないと、実行効率が向上します.欠点:クラスがロードされると初期化され、メモリが浪費されます.これはclassloderメカニズムに基づいてマルチスレッドの同期問題を回避するが、instanceはクラスマウント時にインスタンス化され、クラスマウントの原因は様々であるが、単例モードではgetInstanceメソッドを呼び出すことが多いが、他の方法(または他の静的方法)によるクラスマウントが特定されない.このときinstanceの初期化はlazy loadingの効果に達していないことは明らかである.
コードの例:
4、ダブルチェック/ダブルチェックロック(DCL、すなわちdouble-checked locking)
JDKバージョン:JDK 1.5件
Lazy初期化の有無:Yes
マルチスレッドが安全かどうか:はい
実装の難易度:複雑
説明:この方法はデュアルロックメカニズムを採用し、安全で、マルチスレッドの場合、高性能を維持することができる.getInstance()のパフォーマンスはアプリケーションにとって重要です.
コードの例:
5、登録式/静態内部クラス
Lazy初期化の有無:Yes
マルチスレッドが安全かどうか:はい
実現難易度:一般
説明:この方式は二重ロック方式と同様の効果を達成できるが、より簡単に実現できる.静的ドメインに対して遅延初期化を使用するには、デュアルロック方式ではなく、この方式を使用する必要があります.この方式は静的ドメインの場合にのみ適用され、二重ロック方式は、インスタンスドメインが初期化を遅らせる必要がある場合に使用することができる.この方式は同様にclassloderメカニズムを利用してinstanceの初期化を保証する際に1つのスレッドしかなく、3つ目の方式とは異なり、3つ目の方式はSingletonクラスがマウントされている限り、instanceはインスタンス化され(lazy loading効果に達していない)、この方式はSingletonクラスがマウントされており、instanceは必ずしも初期化されていない.SingletonHolderクラスはアクティブに使用されていないため、getInstanceメソッドを呼び出すとSingletonHolderクラスのマウントが表示され、instanceがインスタンス化されます.想像してみてください.インスタンス化instanceはリソースを消費するので、ロードを遅延させたいと考えています.一方、Singletonクラスのロード時にインスタンス化することは望ましくありません.Singletonクラスが他の場所でアクティブに使用されてロードされる可能性が確保されていないため、このときのインスタンス化instanceは明らかに適切ではありません.このとき、この方式は3つ目の方式に比べて合理的に見えます.
コードの例:
6、列挙
JDKバージョン:JDK 1.5件
Lazy初期化の有無:No
マルチスレッドが安全かどうか:はい
実現難易度:易
説明:この実装方式はまだ広く採用されていないが、これは単一のモードを実現するための最良の方法である.より簡潔で、シーケンス化メカニズムを自動的にサポートし、複数回のインスタンス化を絶対に防止します.この方法はEffective Javaの著者Josh Blochが提唱した方法であり、マルチスレッド同期の問題を回避するだけでなく、シーケンス化メカニズムを自動的にサポートし、逆シーケンス化による新しいオブジェクトの再作成を防止し、複数回のインスタンス化を絶対に防止する.ただし、JDK 1.5になってからenumの特性が加わったので、このように書くのは疎遠に感じられ、実際の仕事でもあまり使われません.reflection attackでプライベート構造メソッドを呼び出すことはできません.
コードの例:
経験談:一般的には、第1種と第2種の怠け者方式は推奨されず、第3種の餓漢方式が推奨されている.第5の登録方式は、lazy loading効果を明確に実現する場合にのみ使用されます.逆シーケンス化に関連してオブジェクトを作成する場合は、6番目の列挙を使用してみてください.他に特別なニーズがある場合は、第4のデュアルロック方式を使用することが考えられる.
Singleton Pattern(Singleton Pattern)はJavaの中で最も簡単な設計モードの一つである.このタイプの設計モードは、オブジェクトを作成するための最適な方法を提供する作成モードに属します.
このモードは、独自のオブジェクトを作成し、単一のオブジェクトのみが作成されることを保証する単一のクラスに関連します.このクラスは、クラスのオブジェクトをインスタンス化する必要がなく、直接アクセスできる独自のオブジェクトにアクセスする方法を提供します.
注意:
紹介する
意図:クラスにインスタンスが1つしかないことを保証し、グローバル・アクセス・ポイントを提供します.
主な解決:グローバルに使用されるクラスが頻繁に作成され、破棄されます.
≪いつ使用|Use|emdw≫:インスタンスの数を制御し、システム・リソースを節約したい場合.
どのように解決するか:システムにこの単例があるかどうかを判断し、ある場合は戻り、ない場合は作成します.
キーコード:コンストラクション関数はプライベートです.
応用例:1、1クラスに1人の担任しかいない.2、Windowsはマルチプロセスマルチスレッドであり、1つのファイルを操作する場合、複数のプロセスまたはスレッドが同時に1つのファイルを操作する現象は避けられないため、すべてのファイルの処理は唯一のインスタンスで行わなければならない.3、一部のデバイスマネージャは、1つのコンピュータに2台のプリンタがあり、出力時に2台のプリンタで同じファイルを印刷できないように処理するなど、単一のモードとして設計されることが多い.
利点:1、メモリにインスタンスが1つしかないため、メモリのオーバーヘッドが削減され、特に頻繁にインスタンスの作成と破棄(管理学院のトップページページキャッシュなど)が行われます.2、資源の多重占有(例えばファイルを書く操作)を避ける.
欠点:インタフェースがなくて、継承することができなくて、単一の職責の原則と衝突して、1つのクラスは内部の論理だけに関心を持つべきで、外がどのように実例化することに関心を持たない.
使用シーン:1、一意のシリアル番号を生産する必要があります.2、WEBのカウンターは、リフレッシュするたびにデータベースに一度加算することなく、一例で先にキャッシュします.3、作成したオブジェクトは、I/Oとデータベースの接続など、消費するリソースが多すぎる.
注意:getInstance()メソッドでは、同期ロックsynchronized(Singleton.class)を使用して、マルチスレッドが同時にinstanceが複数回インスタンス化されることを防止する必要があります.
インプリメンテーション
SingleObjectクラスを作成します.SingleObjectクラスには、そのプライベート構造関数とそれ自体の静的インスタンスがあります.
SingleObjectクラスは、外部から静的インスタンスを取得するための静的メソッドを提供します.SingletonPatternDemo,我々のプレゼンテーションクラスはSingleObjectクラスを使用してSingleObjectオブジェクトを取得する.
ステップ1
Singletonクラスを作成します.
SingleObject.java
public class SingleObject {
// SingleObject
private static SingleObject instance = new SingleObject();
// private,
private SingleObject(){}
//
public static SingleObject getInstance(){
return instance;
}
public void showMessage(){
System.out.println("Hello World!");
}
}
ステップ2
singletonクラスから一意のオブジェクトを取得します.
SingletonPatternDemo.java
public class SingletonPatternDemo {
public static void main(String[] args) {
//
// : SingleObject()
//SingleObject object = new SingleObject();
//
SingleObject object = SingleObject.getInstance();
//
object.showMessage();
}
}
手順3
出力を確認します.
Hello World!
単例モードのいくつかの実現方式
単一のモードの実装には、以下に示すように、いくつかの方法があります.
1、怠け者式、スレッドが安全ではない
Lazy初期化の有無:Yes
マルチスレッドが安全かどうか:いいえ
実現難易度:易
説明:この方式は最も基本的な実現方式であり、この実現の最大の問題はマルチスレッドをサポートしないことである.synchronizedはロックされていないため、厳密には単一のモードではありません.この方式lazy loadingは明らかで,スレッドの安全を要求せず,マルチスレッドでは正常に動作しない.
コードの例:
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
次に説明する実装のいくつかは、マルチスレッドをサポートしていますが、パフォーマンスに違いがあります.
2、怠け者式、スレッド安全
Lazy初期化の有無:Yes
マルチスレッドが安全かどうか:はい
実現難易度:易
説明:この方式はlazy loadingが優れており、マルチスレッドでよく動作することができるが、効率が低く、99%の場合同期を必要としない.利点:メモリの無駄を回避するために、最初の呼び出しで初期化されます.欠点:synchronizedをロックする必要がありますが、ロックは効率に影響します.getInstance()のパフォーマンスはアプリケーションにとって重要ではありません(この方法はあまり頻繁に使用されません).
コードの例:
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3、餓漢式
Lazy初期化の有無:No
マルチスレッドが安全かどうか:はい
実現難易度:易
説明:この方法は一般的ですが、ゴミオブジェクトが発生しやすいです.利点:ロックが付いていないと、実行効率が向上します.欠点:クラスがロードされると初期化され、メモリが浪費されます.これはclassloderメカニズムに基づいてマルチスレッドの同期問題を回避するが、instanceはクラスマウント時にインスタンス化され、クラスマウントの原因は様々であるが、単例モードではgetInstanceメソッドを呼び出すことが多いが、他の方法(または他の静的方法)によるクラスマウントが特定されない.このときinstanceの初期化はlazy loadingの効果に達していないことは明らかである.
コードの例:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
4、ダブルチェック/ダブルチェックロック(DCL、すなわちdouble-checked locking)
JDKバージョン:JDK 1.5件
Lazy初期化の有無:Yes
マルチスレッドが安全かどうか:はい
実装の難易度:複雑
説明:この方法はデュアルロックメカニズムを採用し、安全で、マルチスレッドの場合、高性能を維持することができる.getInstance()のパフォーマンスはアプリケーションにとって重要です.
コードの例:
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
5、登録式/静態内部クラス
Lazy初期化の有無:Yes
マルチスレッドが安全かどうか:はい
実現難易度:一般
説明:この方式は二重ロック方式と同様の効果を達成できるが、より簡単に実現できる.静的ドメインに対して遅延初期化を使用するには、デュアルロック方式ではなく、この方式を使用する必要があります.この方式は静的ドメインの場合にのみ適用され、二重ロック方式は、インスタンスドメインが初期化を遅らせる必要がある場合に使用することができる.この方式は同様にclassloderメカニズムを利用してinstanceの初期化を保証する際に1つのスレッドしかなく、3つ目の方式とは異なり、3つ目の方式はSingletonクラスがマウントされている限り、instanceはインスタンス化され(lazy loading効果に達していない)、この方式はSingletonクラスがマウントされており、instanceは必ずしも初期化されていない.SingletonHolderクラスはアクティブに使用されていないため、getInstanceメソッドを呼び出すとSingletonHolderクラスのマウントが表示され、instanceがインスタンス化されます.想像してみてください.インスタンス化instanceはリソースを消費するので、ロードを遅延させたいと考えています.一方、Singletonクラスのロード時にインスタンス化することは望ましくありません.Singletonクラスが他の場所でアクティブに使用されてロードされる可能性が確保されていないため、このときのインスタンス化instanceは明らかに適切ではありません.このとき、この方式は3つ目の方式に比べて合理的に見えます.
コードの例:
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
6、列挙
JDKバージョン:JDK 1.5件
Lazy初期化の有無:No
マルチスレッドが安全かどうか:はい
実現難易度:易
説明:この実装方式はまだ広く採用されていないが、これは単一のモードを実現するための最良の方法である.より簡潔で、シーケンス化メカニズムを自動的にサポートし、複数回のインスタンス化を絶対に防止します.この方法はEffective Javaの著者Josh Blochが提唱した方法であり、マルチスレッド同期の問題を回避するだけでなく、シーケンス化メカニズムを自動的にサポートし、逆シーケンス化による新しいオブジェクトの再作成を防止し、複数回のインスタンス化を絶対に防止する.ただし、JDK 1.5になってからenumの特性が加わったので、このように書くのは疎遠に感じられ、実際の仕事でもあまり使われません.reflection attackでプライベート構造メソッドを呼び出すことはできません.
コードの例:
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
経験談:一般的には、第1種と第2種の怠け者方式は推奨されず、第3種の餓漢方式が推奨されている.第5の登録方式は、lazy loading効果を明確に実現する場合にのみ使用されます.逆シーケンス化に関連してオブジェクトを作成する場合は、6番目の列挙を使用してみてください.他に特別なニーズがある場合は、第4のデュアルロック方式を使用することが考えられる.