シングルトンデザインパターンは、一般的な使用シナリオモデルタイプを作成する最も簡単な方法である:、システムは唯一のクラスのオブジェクトの1つのインスタンスである、又は頻繁に時間がかかり、頻繁に使用されるリソースを作成できるツールオブジェクトのためオブジェクト。例えば:ビーンデフォルトJDKの例ランタイムクラスはシングルトン空腹であり、Springコンテナはまた、単一の実施形態を飢餓、容器の開始は、もちろん、また、(デフォルト-遅延-INIT =「真」)遅延式に提供され、初期化。別の例では、共通のスレッドプールはまた、Singletonパターンを使用して実施することができるリソースの浪費を作成し、複数のスレッドプールを防止するために、一般的なプログラムスレッドプールの導入です。
飢餓モード
最も簡単なを達成するために、デフォルトの初期化時のクラスのロードが、いくつかの制限、1があり、可能な限り、クラスのロードは、いくつかのリソースの準備ができていない場合、それは別のカスタムクラスローダの数が同時にロードされ、重複して初期化2をもたらすことができます
public class HungrySingleton {
private static final HungrySingleton instance = new HungrySingleton ();
private HungrySingleton () {
// 一定要记得私有化构造器
}
public static HungrySingleton getInstance() {
return instance;
}
}
レイジーモード(安全性の問題をスレッドに注意を払います)
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton () { }
/**
* 一定要记得加synchronized
*/
public static synchronized LazySingleton getInstance() {
if(null == instance) {
instance = new LazySingleton ();
}
return instance;
}
}
デュアル検出モードロック
オブジェクトの完全に初期化されていないインスタンスを取得するには、マルチスレッド環境を、オブジェクトは揮発性の問題で修飾されている防ぐことができ、詳細な分析、下記の注を参照してください。安全上の問題をスレッドに注意を払います
public class DoubleCheckSingleton {
/**
* TODO 这里主要利用了volatile的“顺序性”,保证对instance的写不会发生指令重排而引发其他线程获取到未初始化完全的对象
* TODO 就算没有volatile,“可见性”也可由synchronized保证
*/
private static volatile DoubleCheckSingleton instance = null;
private DoubleCheckSingleton() { }
public static DoubleCheckSingleton getInstance() {
if (null == instance) {
synchronized (DoubleCheckSingleton.class) {
if (null == instance) {
// new DoubleCheckSingleton() 不是原子操作,大体步骤如下
// memory = allocate(); // 1:分配对象的内存空间
// ctorInstance(memory); // 2:初始化对象
// instance = memory; // 3:设置instance指向刚才分配的内存地址
// 伪代码中的2和3之间,可能会被重排序,所以如果执行顺序按1,3,2的话,线程在执行完3后时间片用完切换线程则可能出现未初始化的对象
// 如果用volatile来修饰则会产生写读屏障storeload,禁止2,3的指令重拍,从而防止出现未初始化完全的问题
// TODO 就算时间片用完切换其他线程也进入不了synchronized代码块,因为原来代码块还没执行完成,所以不会释放锁,也不会出现多次实例化
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
静的な内部クラスモード(推奨:JVMのスレッドセーフなコードがシンプルで低エラーが発生しやすいです)
public class InnerClassSingleton {
private InnerClassSingleton() { }
private static class NestClass {
private static final InnerClassSingleton instance = new InnerClassSingleton();
}
public static InnerClassSingleton getInstance() {
// javac编译后,NestClass是一个单独的.class文件,
// 加载InnerClassSingleton.class的时候不会自动加载NestClass.class文件
// 当调用NestClass.instance的时候才会触发JVM加载NestClass类
return NestClass.instance;
}
}
列挙モード
原則と静的な内部クラスと同じで、JVMは、列挙型を反映することができないと、コンストラクタメソッドが一度だけ実行されるようになりますので、シングルトンスレッドセーフ
public class EnumSingleton {
private EnumSingleton() { }
private enum InnerEnum {
/**
* 占位枚举值
*/
enumFactory;
private EnumSingleton instance;
/**
* TODO 注意这里是枚举类的构造器
*/
private InnerEnum() {
instance = new EnumSingleton();
}
public EnumSingleton getInstance() {
return instance;
}
}
public static EnumSingleton getInstance() {
return InnerEnum.enumFactory.getInstance();
}
}