ホームページ >Java >&#&チュートリアル >同時実行のシングルトン モードの詳細な紹介 (コード付き)

同時実行のシングルトン モードの詳細な紹介 (コード付き)

不言
不言転載
2019-04-13 11:59:252663ブラウズ

この記事では、同時実行のシングルトン モードについて詳しく説明します (コード付き)。一定の参考値があります。必要な友人は参照してください。お役に立てれば幸いです。

最もメモリを消費するオブジェクト作成プロセスは制限する必要があります。作成モードとして、シングルトン モード (Singleton) では、アプリケーション内に特定のインスタンスのインスタンスが 1 つだけ存在することが常に維持されます。プログラムのパフォーマンスが大幅に向上します。

以下では、singleton の 4 つの実装方法について説明します。
 单线程下的Singleton的稳定性是极好的,可分为两大类:

1.Eager (Hungry 型): クラスのロード時に即座にオブジェクトを作成します。

public class EagerSingleton {
    //1. 类加载时就立即产生实例对象,通过设置静态变量被外界获取
    //2. 并使用private保证封装安全性
    private static EagerSingleton eagerSingleton  = new EagerSingleton();
    
    //3. 通过构造方法的私有化,不允许外部直接创建对象,确保单例的安全性
    private EagerSingleton(){
    }
    public static EagerSingleton getEagerSingleton(){
        return eagerSingleton;
    }

2. Lazy (遅延型): クラスがロードされてもオブジェクトはすぐには作成されず、最初のユーザーが取得するまでインスタンス化されません。

public class LazySingleton {
    //1. 类加载时并没有创建唯一实例
    private static LazySingleton lazySingleton;
    
    private LazySingleton() {
    }
        
    //2、提供一个获取实例的静态方法
    public static LazySingleton getLazySingleton() {
        if (lazySingleton == null) {
            lazySingleton = new LazySingleton();
        } 
        return lazySingleton;
    }

パフォーマンスの点では、LazySingleton のほうが EagerSingleton より明らかに優れています。クラスの読み込みに多くのリソースが必要な場合 (大きなファイル情報の読み取りなど)、LazySingleton の利点は明らかです。しかし、コードを読めば、致命的な問題を簡単に見つけることができます。 複数のスレッド間でセキュリティを維持するにはどうすればよいですか?

マルチスレッドの同時実行問題を以下で分析します:

この問題を解決する鍵は 2 つの側面にあります: 1. 同期、2. パフォーマンス;

1. まず、同期の問題を解決しましょう: なぜ同期例外が発生するのでしょうか?古典的な例を説明として使用しましょう:
スレッド A とスレッド B が同時に getLazySingleton() を呼び出してインスタンスを取得します。インスタンスが null です。初期化の準備中に、突然スレッド A が一時停止されました。このとき、オブジェクトは正常にインスタンス化されませんでした。後でさらに悪いことが起こりました。スレッド B が実行され、インスタンスも null であると判断されました。このとき、両方の Aそして B がインスタンス化段階に入りました。その結果、2 つのインスタンスが作成され、シングルトンの原則に違反します。

どうやって救出するのか?
Java 開発者として、私は synchronized のことをよく知っています。マルチスレッドのことになると、ほとんどの人は彼を思い浮かべます (JDK6 以降、彼のパフォーマンスは大幅に向上し、解決策は簡単です。同時実行性があり、非常に応用可能です)。

それから、synchronized を使用して問題を解決してみましょう:

//由synchronized进行同步加锁
public synchronized static LazySingleton getLazySingleton() {
        if (lazySingleton == null) {
            lazySingleton = new LazySingleton();
        } 
        return lazySingleton;
    }

同期の問題は解決されたようですが、開発者として最も重要なことはパフォーマンスを確保することです。 synchronized 利点と欠点があります。ロック操作により、コードセグメントは悲観的にロックされ、1 つのリクエストが完了した場合にのみ次のリクエストを実行できます。通常、synchronized キーワードを含むコード部分は、同じ規模のコードよりも数倍遅くなりますが、これは望ましくないことです。では、この問題を回避するにはどうすればよいでしょうか? Java の synchronized の定義には、この提案があります。synchronized を後で使用するほど、パフォーマンスが向上します (洗練されたロック)。

2. したがって、パフォーマンスの問題の解決を開始する必要があります。同期に従って最適化します:

public class DoubleCheckLockSingleton {
    //使用volatile保证每次取值不是从缓存中取,而是从真正对应的内存地址中取.(下文解释)
    private static volatile DoubleCheckLockSingleton doubleCheckLockSingleton;
    
    private DoubleCheckLockSingleton(){
        
    }
    
    public static DoubleCheckLockSingleton getDoubleCheckLockSingleton(){
        //配置双重检查锁(下文解释)
        if(doubleCheckLockSingleton == null){
            synchronized (DoubleCheckLockSingleton.class) {
                if(doubleCheckLockSingleton == null){
                    doubleCheckLockSingleton = new DoubleCheckLockSingleton();
                }
            }
        }
        return doubleCheckLockSingleton;
    }
}

上記のソース コードは、古典的な volatile キーワード (JDK1.5 以降に生まれ変わった) Double Check Lock (DoubleCheck) であり、最大程度 同期によって生じるパフォーマンスのオーバーヘッド。 VolatileとDoubleCheckについては後述します。


1.volatile

は、JDK1.5 以降に正式に実装されて使用されました。以前のバージョンでは、このキーワードのみが定義されており、具体的な実装はありませんでした。 volatile を理解したい場合は、JVM 自体のメモリ管理についてある程度理解する必要があります。


1.1

ムーアの法則に従うと、メモリの読み取りおよび書き込み速度は満足のいくものとは程遠いです。現代のコンピュータでは、CPU にキャッシュを追加するメカニズムが導入されています。キャッシュはメモリの値を先読みし、一時的にキャッシュに保存し、計算を通じてメモリ内の対応する値を更新します。

**1.2** JVM は PC のアプローチを模倣し、独自の **作業メモリ** をメモリ内に分割します。メモリのこの部分はキャッシュと同じように機能するため、JVM の動作が大幅に向上します。効率的ですが、すべてに長所と短所があり、このアプローチでは、作業記憶が他の記憶と通信するときに伝達の問題も引き起こします。 volatile の機能の 1 つは、キャッシュとメモリ間の不一致を避けるために、メモリから最新の値を強制的に読み取ることです。

1.3

volatile のもう 1 つの機能も JVM に関連しています。つまり、JVM は独自の判断を使用して、ソース コード# の実行順序を並べ替えます。 ## 命令パイプラインの一貫性を確保して、最適な実行計画を達成します。このアプローチによりパフォーマンスは向上しますが、DoubleCheck に予期しない結果が生じ、2 つのスレッドが相互に干渉する可能性があります。 Volatile は、オブジェクトが妨害されず、安全な安定性を確保できるように、事前発生保証 (書き込みが読み取りよりも優先される) を提供します。

2.DoubleCheck

これは現代のプログラミングの遺産であり、同期ブロックに入った後、オブジェクトがインスタンス化されていると想定されており、判断はまた作られる。

もちろん、

公式が推奨するシングルトン実装方法

もあります: ######クラスの構築は定義においてすでにアトミックであるため、上記の問題は解決されます再度生成されることはありませんが、シングルトンの実装方法としては優れており、推奨されます。 ###rree

以上が同時実行のシングルトン モードの詳細な紹介 (コード付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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