ホームページ  >  記事  >  Java  >  Java シングルトン モードで Hungry Man パターンと Lazy Man パターンを実装する方法の詳細な説明

Java シングルトン モードで Hungry Man パターンと Lazy Man パターンを実装する方法の詳細な説明

PHPz
PHPz転載
2023-04-27 12:40:071442ブラウズ

シングルトン モードとは

複数のインスタンスを作成するのではなく、プログラム内に特定のクラスのインスタンスが 1 つだけ存在するようにすると、効率が向上します。

単一インタレスト モードでは、通常、インスタンス オブジェクトを取得するために getInstance() メソッドが 1 つだけ提供され、setInstance() メソッドは提供されません。これは、他のインスタンス オブジェクトのインスタンス化を避けるためです。

シングルトン モードには 2 つのモードがあります。1 つはハングリーマン モード、もう 1 つは怠け者モードです。

1. ハングリー ハン モード

1. ハングリー ハン モードの概念

ハングリー ハン モードとは、クラスがロードされるとすぐにインスタンス化され、以降の使用でのみ表示されます。

2. ハングリー モード コード
package thread.example;
//饿汉模式
public class HungrySingle {
//在类加载的时候就实例化了,类加载只有一次,所以值实例化出了一份该实例对象
    private static HungrySingle instance = new HungrySingle();
    public static HungrySingle getInstance() {
        return instance;
    }
}
3. マルチスレッドはスレッドセーフですか?

クラスがロードされたときにすでにインスタンス化されているため、インスタンス化は行われませんインスタンス化された変更操作は読み取り操作のみです。マルチスレッド状況ではスレッドセーフです。

2. 遅延モード

1. 遅延モードの概念

は、クラスがロードされたときに直接インスタンス化されませんが、指定されたインスタンス メソッドが呼び出されたときにインスタンス化されます。 , これにより、使用したくないときにインスタンス化されなくなります。一般的に言えば、Hungry Man モードよりも効率的です。

2. シングルスレッド環境での遅延モード
package thread.example;
//单线程的懒汉模式
public class LazySingle {
    private static LazySingle instance = null;
    //只有在调用该方法的时候才实例化
    public static LazySingle getInstance() {
        if(instance == null) {
            instance = new LazySingle();
        }
        return instance;
    }
}
3. マルチスレッド環境での遅延モード

(1) マルチスレッド環境での遅延モードの不整合の原因となります。状況 セキュリティ上の理由

マルチスレッドの場合、両方のスレッドが、instance=null のコピーを取得する可能性があります。これは、スレッド 1 が自身の郡のインスタンスを変更する場合、スレッド 1 がインスタンスを変更する時間がないためです。これにより、スレッド 2 もインスタンス オブジェクトをインスタンス化し、この時点ではシングルトン モードではなくなります。この問題の主な原因は、インスタンスの変更によってアトミック性が失われることにありますが、アトミック性を確保するために、スレッドセーフを実現するためのロックを考えました。

(2) 解決策コード例

バージョン 1

package thread.example;
//多线程安全下的懒汉模式
    public class LazySingle {
        private LazySingle() {
    }
    private static LazySingle instance = null;
    //只有在调用该方法的时候才实例化
    public static synchronized LazySingle getInstance() {
        if (instance == null) {
            instance = new LazySingle();
        }
        return instance;
    }
}

バージョン 1 のコードはスレッド セーフを保証しますが、メソッドが呼び出されるたびにロックが発生します。ロック解除の問題をさらに最適化するために、ロックの粒度を減らして効率を向上させることができます。ロックを追加すると、高い同時実行性を達成できなくなるためですが、それでも効率を向上させたいので、それを最適化します。

バージョン 2

Double if 判定ロックにより効率が向上

package thread.example;
 
public class SecurityLazyModle {
    private LazySingle() {
    }
    private static volatile SecurityLazyModle instance = null;//保证内存可见性,防止编译器过度优化(指令重排序)
    public static SecurityLazyModle getInstance() {
        if(instance == null) {
            synchronized (SecurityLazyModle.class) {
                if(instance == null) {
                    instance = new SecurityLazyModle();
                }
            }
        }
        return instance;
    }
}

バージョン 2 の説明

if の最初の層は、現在の状態かどうかを判断することです。インスタンスが作成されると、同期の 2 番目のレベルは、現在の if に入るスレッドがロックを競合できるようにすることです。ロックを取得したスレッドが if の 3 番目のレベルに入ると、そのスレッドが空であるかどうかが判断されます。空の場合、オブジェクトをインスタンス化してから解放します。ロックの場合、ロックが解放された後、インスタンスは空ではなくなり、後続のスレッドは 3 番目の層でブロックされます。後で getInstance() メソッドにアクセスすると、それが見つかります。インスタンスはもう空ではないため、プリエンプトする必要はありません。競合するロックも多くの時間を消費するため、リソースをロックします。このように処理することで、スレッドの安全性が確保され、効率が向上します。

#ここで volatile を使用する目的は、コンパイラの最適化によって引き起こされる命令の並べ替えを防ぐことです。新しいオブジェクトの実行はアトミックな操作ではなく、次の 3 つのステップに分けることができます:

  1. 1. メモリ領域の割り当て

  2. 2. オブジェクトのインスタンス化

  3. ##3. 変数への値の代入

上記の実行で、1 と 3 が最初に実行されると (2 がまだ完了していないと仮定して)、if の最初の層の外側のスレッドは、この時点で null ではないと判断します。この時点でオブジェクトは直接返されますが、このオブジェクトはまだ途中までしか実行されていないため、その後使用するとスレッド セーフティの問題が発生します。

Volatile は、外部スレッドを実行する前に、これら 3 つのステップを実行する必要があることを保証できます (順序に関係なく、最終的には実行されます)。この時点で、オブジェクトの整合性が保証されます。

以上がJava シングルトン モードで Hungry Man パターンと Lazy Man パターンを実装する方法の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。