シングルトンモード
シングルトンパターンは、デザインパターンの中で最も単純なデザインパターンの1つである可能性があり、最も一般的に使用されるデザインパターンの1つである可能性もあります。
シングルトンパターンは、クラスのインスタンスが1つだけであることを保証します。アイデアは、コンストラクターを民営化することです。インスタンスの数を制御したい場合は、シングルトンパターンの使用を検討できます。
日常生活では、人が直属の上司であり、データベースの接続プールが繰り返し作成されることはありません。これらはシングルトンの例です。
シングルトンモードを実装する方法はたくさんあります。主に、レイジーマンモードをサポートするかどうか、スレッドセーフでさまざまな手法を使用するかどうかの実装です。もちろん、遅延読み込みを考慮する必要のないシナリオ、つまり遅延モードがいくつかあり、外部呼び出しの処理に静的静的クラスまたは属性とメソッドを直接使用します。
7つのシングルトンパターンの実現
1.スラッカーモード(スレッドは安全ではありません)
実装は非常に簡単で、インスタンスがないときにインスタンスを作成するだけです。インスタンスは、初めて使用するときにのみ作成されます。ロックがないため、スレッドセーフではないため、マルチスレッドモードはサポートされていません。
public class LazyMan(){
private LazyMan(){
//私有化构造方法
}
private static LazyMan lazyMan;
public static LazyMan getInstance(){
if(lazyMan == null){
lazy = new LazyMan();
}
return lazyMan;
}
}
2.レイジーマンモード(スレッドセーフ)
ロック後、スレッドセーフは達成されますが、効率が低下します
public class LazyMan(){
private LazyMan(){
//私有化构造方法
}
private static LazyMan lazyMan;
public static synchronized LazyMan getInstance(){
if(lazyMan == null){
lazy = new LazyMan();
}
return lazyMan;
}
}
}
3.空腹の男モード
名前が示すように、彼らは空腹で喉が渇いていて、空腹と喉の渇きのレベルは私のものと同じです。ロックがないため、実行効率は非常に高くなりますが、メモリの浪費につながる可能性があります。
public class Hungry(){
private Hungry(){
}
private final static Hungry hungry = new Hungry();
public static Hungry getInstance(){
return hungry;
}
}
4.内部クラス(スレッドセーフ)
クラスの静的内部クラスを使用して実装されたシングルトンモードは、スレッドセーフを保証するだけでなく、遅延読み込みも保証すると同時に、ロック方法のためにパフォーマンスを消費しません。これは主に、JVM仮想マシンがマルチスレッド同時アクセスの正確さを保証できるためです。つまり、クラスの構築メソッドをマルチスレッド環境に正しくロードできるためです。
public class Holder(){
private Holder(){
}
public static class InnerClass(){
private final static Holder holder = new Holder();
}
public static Holder getInstance(){
return InnerClass.holder;
}
}
5.二重検出ロックモード(DCL)
ダブルロック方式は、メソッドレベルのロックを最適化したもので、インスタンスの取得にかかる時間のかかる部分を減らし、遅延読み込みモードも満たします。
public class LazyMan(){
private LazyMan(){
}
private volatile static LazyMan lazyMan;//必须加上volatile保证
public static LazyMan getInstance(){
if(lazyMan == null){
synchronized(LazyMan.class){
if(lazyMan==null){
lazyMan = new LazyMan();//不是原子性操作
}
}
}
return lazyMan;
}
6. CAS「AtomicReference」(スレッドセーフ)
AtomicReferenceは、Java Concurrency Libraryによって提供されるアトミッククラスAtomicReferenceを介して、同時アクセスをサポートするジェネリックインスタンスをカプセル化できます。
CASを使用する利点は、スレッドセーフを確保するために従来のロック方法を使用する必要がないことですが、スレッドセーフを確保するためにCASのビジーアルゴリズムと基盤となるハードウェアの実装に依存しています。他のロック実装と比較して、スレッドの切り替えやブロッキングがなく、追加のオーバーヘッドがなく、より大きな同時実行性をサポートできます。しかし、それはビジー待機を生成し、そうでない場合は、無限ループを維持します。
public class Singleton(){
private Singleton(){
}
private static Singleton singleton;
private static final AtomicReference<Singleton> INSTANCE = new AtomicReference();
public static final Singleton getInstance() {
for (; ; ) {
Singleton singleton = INSTANCE.get();
if (singleton != null) return singleton;
INSTANCE.compareAndSet(null, new Singleton());
return INSTANCE.get();
}
}
}
7.列挙
この書き込み方法は、一般的なドメイン方法と機能が似ていますが、より簡潔で、補正なしのシリアル化メカニズムを提供します。複雑なシリアル化やリフレクション攻撃に対抗する場合でも、これのインスタンス化を完全に防ぎます。この方法は広く採用されていませんが、単一要素列挙型がシングルトンを実装するための最良の方法になり、EffectiveJavaの作成者によって推奨されています。継承の場合は利用できないことに注意してください。
public enum Singleton(){
INSTANCE;
public void method(){
}
}
@Test
public void test() {
Singleton.INSTANCE.method();
}
概要:シングルトンモードは比較的単純ですが、開発では非常に一般的です。通常の開発では、このクラスが遅延読み込みなしでグローバルに利用可能であることを確認できる場合は、直接作成して外部から呼び出すことができます。ただし、クラスが多数あり、ユーザーが特定の条件(ゲームレベル)をトリガーした後に表示する必要があるクラスがある場合は、遅延読み込みを使用する必要があります。