Singletonパターンは限り資格の開発者が記述しますようであると言うことができますが、あなたが一番下に取得したい場合は、小さなシングルトンは、次のような多くのもの、含むことができる:マルチスレッドセーフ?遅延ロードはありますか?パフォーマンスのように。あなたは、いくつか書かれたシングルトンはそれがあります知っていますか?ダメージ反射モードの単一のケースを防ぐためにどのように?
、シングルトン
1.1定義
シングルトンは、グローバルにユニークなオブジェクトを作成するために、一度だけインスタンス化されたプログラムの実行です。以下のようなビット Java
静的変数が、Singletonパターンは、静的変数に優れています:
- プログラムが起動は静的変数
JVM
使用されていない場合は、ロードされるリソースの浪費の原因となります。 - Singletonパターンは、遅延ロードを有効にし、あなただけのインスタンスを使用する場合、インスタンスを作成するために行くことができます。
開発ツール、ライブラリの多くのツールが、彼らは唯一のあなたが複数のインスタンスを作成する場合、オブジェクトを作成する必要があるなど、予測できない問題につながる可能性がシングルトンモード、スレッドプールの割合は、キャッシュ、ログや他のオブジェクトに適用されます資源の浪費は、矛盾した結果やその他の問題に対処します。
1.2の単一の実施形態のアイデア
- 静的オブジェクトの例としては、
- コンストラクタの民営化、施工方法を禁止することによってインスタンスを作成します。
- これは、一意のインスタンスを返すためのpublic staticメソッドを提供します。
1.3の単一例のメリット
- 1つのオブジェクトのみ、少ないメモリを費やして、良好なパフォーマンス。
- リソースの複数の割り当てを避けてください。
- システム、最適化、共有リソースへのアクセスにグローバルアクセスポイントを設定します。
第二に、シングルモードで
- 飢えモード
- レイジーモード
- ダブルチェックロックモード
- 内部の静的タイプシングルトン
- 例シングルモードの列挙クラス
2.1飢えモード
静的プロパティを定義する場合、オブジェクトを直接インスタンス化
public class HungryMode {
/** * 利用静态变量来存储唯一实例 */ private static final HungryMode instance = new HungryMode(); /** * 私有化构造函数 */ private HungryMode(){ // 里面可以有很多操作 } /** * 提供公开获取实例接口 * @return */ public static HungryMode getInstance(){ return instance; } }
2.1.1利点
使用に起因するstatic
キーワードこの変数を参照するとき、そう、この変数書き込み操作の完全であることを確実にするために、これを保証するためにJVM
、スレッドの安全性のレベルを
2.1.2短所
私たちは、このクラスをロードするために初期化され、大類推、あれば、私たちは、メモリ空間の浪費につながる、長い時間のためにこのクラスを使用していませんでした:レイジーローディングはスペースの無駄が生じ、達成することはできません。
したがって、だけで使用することができない
getInstance()
だけシングルトンクラスを初期化するために、方法は、データシングルトンクラスをロードします。だから:怠惰なスタイル。
2.2レイジー・モード
レイジーモードは、プログラムが初期化されるときに、インスタンスを作成していないモードを飢えに起因する無駄なスペースの問題を解決するために、その怠惰なモードの例を使用している場合にのみ、インスタンスを作成します、怠惰なモードです。
一般的には、怠惰なモードを達成するために2.2.1
public class LazyMode {
/** * 定义静态变量时,未初始化实例 */ private static LazyMode instance; /** * 私有化构造函数 */ private LazyMode(){ // 里面可以有很多操作 } /** * 提供公开获取实例接口 * @return */ public static LazyMode getInstance(){ // 使用时,先判断实例是否为空,如果实例为空,则实例化对象 if (instance == null) { instance = new LazyMode(); } return instance; } }
しかし、複数のスレッドの場合は、この実現は発生状況の複数のインスタンスがあるかもしれない、安全ではありません。
if (instance == null) {
instance = new LazyMode();
}
全く保全対策がないので、2つのスレッドが、上記のコードにあると仮定し、したがって2つのスレッドが同時に決定することができる instance
空で、インスタンスを初期化するために行きますので、状況は、複数のインスタンスが存在することになります。
最適化2.2.2レイジー・モード
私たちは与えるgetInstance()
方法は、追加synchronized
のキーワードgetInstance()
メソッドが保護されたリソースは、複数のインスタンスの問題を解決することができるようになりますとなりましたが。
public class LazyModeSynchronized {
/** * 定义静态变量时,未初始化实例 */ private static LazyModeSynchronized instance; /** * 私有化构造函数 */ private LazyModeSynchronized(){ // 里面可以有很多操作 } /** * 提供公开获取实例接口 * @return */ public synchronized static LazyModeSynchronized getInstance(){ /** * 添加class类锁,影响了性能,加锁之后将代码进行了串行化, * 我们的代码块绝大部分是读操作,在读操作的情况下,代码线程是安全的 * */ if (instance == null) { instance = new LazyModeSynchronized(); } return instance; } }
怠惰2.2.3モデルの利点
これは、メモリ空間を節約し、遅延ロードを実装しています。
2.2.4欠点レイジー・モード
- ロック解除され、スレッドセーフの場合には、複数のインスタンスが発生する可能性があります。
- ロックの場合、プログラムは、システムが深刻なパフォーマンスの問題を持って、シリアライズされます。
レイジーモードロックの問題は、のためgetInstance()
の方法、操作の大半は読み出し動作がスレッドセーフで、読み取り操作をしているので、我々は、各スレッドは、このメソッドを呼び出す前にロックを保持しなければならせません、我々は調整する必要があります問題をロックします。これはまた、新しい実装モデルを作成:ダブルロックモードを確認してください。
2.3ダブルチェックロックモード
2.3.1二重チェックはロックモードは、一般的に実現されています
public class DoubleCheckLockMode {
private static DoubleCheckLockMode instance; /** * 私有化构造函数 */ private DoubleCheckLockMode(){ } /** * 提供公开获取实例接口 * @return */ public static DoubleCheckLockMode getInstance(){ // 第一次判断,如果这里为空,不进入抢锁阶段,直接返回实例 if (instance == null) { synchronized (DoubleCheckLockMode.class) { // 抢到锁之后再次判断是否为空 if (instance == null) { instance = new DoubleCheckLockMode(); } } } return instance; } }
単一のケースを解決するためのロックモードをダブルチェック、性能、セキュリティスレッドが、そのようなアプローチは、問題がある:問題があるため、マルチスレッドの場合には、ヌルポインタ問題がある可能性があり発生JVM
がされるときにオブジェクトのインスタンスに最適化し、演算命令を並べ替えます。
コマンド転位は何2.3.2?
private SingletonObject(){
// 第一步 int x = 10; // 第二步 int y = 30; // 第三步 Object o = new Object(); }
上記のコンストラクタはSingletonObject()
、JVM
それは命令並べ替えとなり、実行順序が混乱することができるが、それは実行順序の一種であるかどうか、JVM
そして最終的にそれがインスタンス化され、すべてのインスタンスの完了を確実にします。 コンストラクタ操作が比較的長い場合には、効率を向上させるために、JVM
インスタンス化された属性が完了していないコンストラクタの内側になり、オブジェクトが返されます。理由は二重のNULLポインタロック検出問題は、あるスレッドが起因して、他のスレッドのインスタンスに、直接アクセスインスタンス化ロックを取得すると、ここに表示されるようにされJVM
、他のスレッドのオブジェクトが完全に取得できない場合があります理由の命令の並べ替えオブジェクト、インスタンスを使用するときにnullポインタ例外の問題になります。
2.3.3ダブルチェックロックモードの最適化
問題は、二重チェックのnullポインタ例外にロックモードを引き起こし解決するために、のみ使用する必要があるvolatile
キーワードを、volatile
キーワードは、厳密に従うhappens-before
ことを原則:読み出し動作の前に、書き込み操作が完了する必要があります。
public class DoubleCheckLockModelVolatile {
/** * 添加volatile关键字,保证在读操作前,写操作必须全部完成 */ private static volatile DoubleCheckLockModelVolatile instance; /** * 私有化构造函数 */ private DoubleCheckLockModelVolatile(){ } /** * 提供公开获取实例接口 * @return */ public static DoubleCheckLockModelVolatile getInstance(){ if (instance == null) { synchronized (DoubleCheckLockModelVolatile.class) { if (instance == null) { instance = new DoubleCheckLockModelVolatile(); } } } return instance; } }
2.4静的な内部クラスモード
ので、静的内部クラスモードも、内部クラスのインスタンスを作成し、所有者モードの単一のケースと呼ばれる JVM
意志が外部クラスをロードするプロセスである、それが呼び出され、静的な内部クラス、クラス/メソッドの内部でのみプロパティをロードされていませんロードし、その静的プロパティを初期化します。静的プロパティは、static
一度だけインスタンス化され、かつ厳密にインスタンス化の順序を保証することを確認するように変更します。
public class StaticInnerClassMode {
private StaticInnerClassMode(){ } /** * 单例持有者 */ private static class InstanceHolder{ private final static StaticInnerClassMode instance = new StaticInnerClassMode(); } /** * 提供公开获取实例接口 * @return */ public static StaticInnerClassMode getInstance(){ // 调用内部类属性 return InstanceHolder.instance; } }
このように、メカニズムと空腹の男のタイプの方法が似ていますが、異なる採用しました。そのようなメカニズムの両方は、そのローディングを一つだけスレッドのインスタンスの初期化を確実にするために使用されます。さまざまな場所:
- 限り式のように飢え
Singleton
ロードされたクラスは、何らインスタンス化されませんLazy-Loading
効果。 - 道のstatic内部クラス
Singleton
のクラスがロードされ、すぐにではないインスタンス化が、必要がインスタンス化する際に、呼び出しているgetInstance()
メソッドがロードされますSingletonInstance
完了するために、クラスをSingleton
インスタンス化します。
クラスの静的プロパティはまず、クラスはので、ここでは、初期化されている場合にのみロードされたJVM
クラスが初期化されるとき、他のスレッドがアクセス不能で、セキュリティスレッドを確実に私たちを助けるために。
したがって、この方法では、マルチスレッドの安全性を確保するために、および任意のパフォーマンスへの影響とスペースを無駄にしませんでしたすべてのロックを追加せず。
2.5列挙クラスはシングルトンを実装します
列挙型は、スレッドセーフ、および一度だけロードされ、列挙シングルトンパターンを達成するために、この機能のデザイナーフルに活用されているので、列挙言葉遣いは非常にシンプルですが、列挙型は、単一の場合達成するために使用されたCDを実現の単一の実施形態モードの11種類が損傷されていません。
public class EnumerationMode {
private EnumerationMode(){ } /** * 枚举类型是线程安全的,并且只会装载一次 */ private enum Singleton{ INSTANCE; private final EnumerationMode instance; Singleton(){ instance = new EnumerationMode(); } private EnumerationMode getInstance(){ return instance; } } public static EnumerationMode getInstance(){ return Singleton.INSTANCE.getInstance(); } }
アプリケーション:
- 私たちは頻繁にオブジェクトを作成し、破壊する必要があります。
- あなたはあまりにも多くを消費するオブジェクトを作成したり、あまりにも多くのリソースを費やしていますが、頻繁に使用するオブジェクト場合には、
- ツールオブジェクト。
- オブジェクトデータベースや、頻繁にアクセスされるファイル。
第三に、問題と解決策のシングルトンパターン
添加を列挙し、他の方法は、反射的、単一の実施形態によって破壊されます
Singletonパターンは、3.1を破壊します
/**
* 以静态内部类实现为例
* @throws Exception
*/
@Test
public void singletonTest() throws Exception { Constructor constructor = StaticInnerClassMode.class.getDeclaredConstructor(); constructor.setAccessible(true); StaticInnerClassMode obj1 = StaticInnerClassMode.getInstance(); StaticInnerClassMode obj2 = StaticInnerClassMode.getInstance(); StaticInnerClassMode obj3 = (StaticInnerClassMode) constructor.newInstance(); System.out.println("输出结果为:"+obj1.hashCode()+"," +obj2.hashCode()+","+obj3.hashCode()); }
印刷コンソール:
输出结果为:1454171136,1454171136,1195396074
結果から、我々は、出力見ることができるobj1
とobj2
同じオブジェクト、obj3
新しいオブジェクトを。obj3
私たちは、今度はプライベートコンストラクタを呼び出し、新しいオブジェクトを作成し、反射、です。
損傷の単一のケースを防ぐために、どのように3.2
設定プロセスで決定することができる次のように、インスタンスは、溶液は、新しいインスタンスの形成を防止する、そこRuoyi。
public class StaticInnerClassModeProtection {
private static boolean flag = false; private StaticInnerClassModeProtection(){ synchronized(StaticInnerClassModeProtection.class){ if(flag == false){ flag = true; }else { throw new RuntimeException("实例已经存在,请通过 getInstance()方法获取!"); } } } /** * 单例持有者 */ private static class InstanceHolder{ private final static StaticInnerClassModeProtection instance = new StaticInnerClassModeProtection(); } /** * 提供公开获取实例接口 * @return */ public static StaticInnerClassModeProtection getInstance(){ // 调用内部类属性 return InstanceHolder.instance; } }
テスト:
/**
* 在构造方法中进行判断,若存在则抛出RuntimeException
* @throws Exception
*/
@Test
public void destroyTest() throws Exception { Constructor constructor = StaticInnerClassModeProtection.class.getDeclaredConstructor(); constructor.setAccessible(true); StaticInnerClassModeProtection obj1 = StaticInnerClassModeProtection.getInstance(); StaticInnerClassModeProtection obj2 = StaticInnerClassModeProtection.getInstance(); StaticInnerClassModeProtection obj3 = (StaticInnerClassModeProtection) constructor.newInstance(); System.out.println("输出结果为:"+obj1.hashCode()+"," +obj2.hashCode()+","+obj3.hashCode()); }
印刷コンソール:
Caused by: java.lang.RuntimeException: 实例已经存在,请通过 getInstance()方法获取! at cn.van.singleton.demo.mode.StaticInnerClassModeProtection.<init>(StaticInnerClassModeProtection.java:22) ... 35 more
IVの概要
の種々の実施の4.1比較
名前 | 飢えモード | レイジーモード | ダブルチェックロックモード | 静的な内部クラス | 列挙型クラスの実装 |
---|---|---|---|---|---|
可用性 | 利用できます | お勧めできません | 推奨 | 推奨 | 推奨 |
機能 | レイジーローディングが達成できない、それはスペースの無駄をもたらすことができます | スレッドセーフのロックを解除し、パフォーマンスの低下をロック | スレッドセーフな、遅延ロード、高効率 | スレッド安全ではない、遅延ロード、高効率化を避けます。 | シンプルなライティング、スレッドセーフ;一度だけロード |