マルチスレッド・シングル・ケース・モデル:遅延読み込み(遅延ロード)とリアルタイム負荷

 

開発では、多くのシステムリソースを消費する必要性のインスタンスを作成するので、私たちは通常、利益がシングルトンモードで得られた場合にのみ、この例を使用するときのインスタンスを作成しますレイジーローディング機構を、使用している場合アプリケーションの広い範囲。このメカニズムは、シングルスレッド環境の実現に非常に簡単です、しかし、マルチスレッド環境でのリスクがあります。この記事では、慣性ローディング機構とマルチスレッド環境での使用に焦点を当てています。(著のnumberzero、IBMの記事「ダブルチェックロックとSingletonパターン」、転載することを歓迎し、議論を参照してください)

1、ロード不活性シングルトン
我々はシングルトンクラスを設計するとき、クラス内、およびへのアクセスを提供する静的getInstanceメソッド外クラス(コンストラクタ、または直接に定義された作成)を構築します。通常方法シングルトンオブジェクト。例えば:

コードをコピー
コードをコピー
パブリッククラスシングルトン         
{         
    プライベート静的シングルトンインスタンス=新しいシングルトン()。        
    プライベートシングルトン(){         
        ...         
    }         
    パブリック静的シングルトンのgetInstance(){         
             インスタンスを返します。         
    }         
}
コードをコピー
コードをコピー

私たちは、このインスタンスの時間を必要としないかもしれないときに最初にロードクラスでもシングルトンインスタンスを使用して作成され、そのような結果と我々は異なる期待するためのインスタンスを作成します。欠点は、このコードはということです。そして、この場合には、システムリソースを消費するシングルトンインスタンスを作成し、常にシングルトンインスタンスを使用していないアプリケーションは、シングルトンで消費されるシステムリソースの作成が無駄にされました。

これを避けるために、我々は通常時にのみ使用されて作成しようとしている遅延ロード・メカニズムを使用します。次のように遅延ロード上記のコードのコードです。

コードをコピー
コードをコピー
パブリッククラスシングルトン{         
    プライベート静的シングルトンインスタンス= NULL;        
    プライベートシングルトン(){         
        ...         
    }         
    パブリック静的シングルトンのgetInstance(){         
        IF(例えば== NULL)         
            インスタンス=新しいシングルトン()。         
                インスタンスを返します。         
    }         
}       
コードをコピー
コードをコピー

図2に示すように、遅延ロードのマルチスレッドの問題
:抽出された第1のコードをロードされた不活性   

パブリック静的シングルトンのgetInstance(){         
    IF(例えば== NULL)         
    インスタンス=新しいシングルトン()。         
    インスタンスを返します。         
}      

 二つのスレッドAとBが同時にメソッドが実行され、その後、次のように行わ場合には、次のとおりです。

1.判決fooがnullのときににあれば、入力された場合

2. Bが入力した場合、FOOもヌルであるので、次にAは、FOOを作成されていない、及びBも入る従ってかどうかを決定します

3. Aは、fooとリターンを作成します

4. Bはまた、fooとリターンを作成します

この時点で、問題は、私たちが期待したものではありませんこれは、私たちのシングルトンが二回作成され、発生します。

3つのソリューションとその問題
3.1クラスのロック機構
上の問題のほとんど直感的な解決策は一つだけ呼び出す準備ができてgetInstanceメソッドを可能にしたgetInstanceプレフィックスを、同期させるための方法を追加することです:

パブリック静的同期シングルトンのgetInstance(){         
    IF(例えば== NULL)         
    インスタンス=新しいシングルトン()。         
    インスタンスを返します。         
}       

    このような解決策は確かにエラーの発生を防ぐことができますが、それは非常にパフォーマンスに影響を与えている:シングルトンがロックを取得する必要がありgetInstanceメソッドへの各呼び出しは、実際には、インスタンスが作成された単一の場合の後、後続の要求は必要ありませんその後、相互排他メカニズムを使用します

3.2ダブルチェックロッキング
一度誰か上記の問題を解決するために、ダブルチェックロッキング・ソリューションを

コードをコピー
コードをコピー
パブリック静的シングルトンのgetInstance(){         
    IF(例えば== NULL)         
        同期(インスタンス){         
            IF(例えば== NULL)         
                インスタンス=新しいシングルトン()。        
        }         
    インスタンスを返します。         
}
コードをコピー
コードをコピー

 のは、このコードがどのように機能するかを見てみましょう。まず、スレッドが要求を出したときに、それが最初のようにそれが取る同期ブロックにリソースを避けて、その内容に戻り、直接そのインスタンスがnullであるかどうかをチェックし、もしません。第二に、偶数セクション2に記載されている場合、裁判官が、それらはまたためにコードの同期ブロックを実行しなければならない場合は、コードの最初のスレッドブロックが、新しいエントリを作成する最初に、二つのスレッドを発生場合、彼らは追加のインスタンスを作成せず、判断を渡すことはできませんので、シングルトンインスタンス、およびそれ以降のスレッドがあります。

         上記の説明は、すべて私たちの問題を解決しているようだが、実際には、ビューのJVMの観点から、コードはまだエラーが発生する可能性があります。

         JVMの場合は、1つのJava命令を実行しています。Javaの命令でオブジェクトと代入演算子を作成するには、そのインスタンス=新しいシングルトン()、別々に行われ、文は二つのステップで実行されます。しかし、JVMは、シングルトンインスタンスを初期化するために行く、新しいJVMインスタンスが存在する可能性があることを意味シングルトンはスペースを割り当てる、これら二つの動作の順序を保証し、その後、直接割り当てられたインスタンスメンバはありません。これは、できるだけミスをします、我々はまだA、B二つのスレッド、例えば:

最初かどうかを決定するには1. A、Bのスレッド

2. Aは、最初のインスタンスがヌルであるため、それがインスタンス=新しいシングルトン()を実行し、同期ブロックに入ります。

3. JVM、第1の延伸ブランクメモリシングルトンインスタンスに割り当てられ、メンバーインスタンスに割り当てられたJVM番号内部最適化機構ので(この場合は、初期化JVMこの例を開始しないことに注意)、その後同期ブロックを残しました。

4. Bは、この時間インスタンスがnullではないので、それは直ちに同期ブロックを左に、同期ブロックに入り、メソッドを呼び出したプログラムに結果を返します。

このとき5.スレッドBシングルトンインスタンスが使用することを意図したが、それは、初期化されていないエラーが発生していることがわかりました。

マルチスレッド環境でシングルトンが内部4クラスによって実現され
、ロードに時間がかかる達成するために、すべての時間のgetInstance呼び出し相互に排他的で実行する必要はしたくない、最良かつ最も便利なソリューションは、次のとおりです。

コードをコピー
コードをコピー
パブリッククラスシングルトン{         
    プライベートシングルトン(){         
        ...         
    }         
    プライベート静的クラスSingletonContainer {         
        プライベート静的シングルトンインスタンス=新しいシングルトン()。        
    }         
    パブリック静的シングルトンのgetInstance(){         
        SingletonContainer.instanceを返します。        
    }         
}   
コードをコピー
コードをコピー

     JVM内部機構は、クラスがロードされたとき、このクラスのロード処理が相互に排他的スレッドであることを保証します。だから我々は最初のgetInstanceを呼び出すときに、JVMは、そのインスタンスを確実に私たちを助けることができることを一度だけ作成され、インスタンスに割り当てられたメモリが初期化されていることを確認しますので、我々は3.2を心配しないでください。また、この方法は、最初の呼び出しの際に相互排他メカニズムを使用しますが、これは3.1の非効率性を解決します。あなたの最初のロードSingletonContainerクラス、およびSingletonContainerクラスはgetInstanceメソッドを呼び出すときにのみロードされ、したがって、遅延ロードを達成したときの最後のインスタンスが作成されます。

開発では、多くのシステムリソースを消費する必要性のインスタンスを作成するので、私たちは通常、利益がシングルトンモードで得られた場合にのみ、この例を使用するときのインスタンスを作成しますレイジーローディング機構を、使用している場合アプリケーションの広い範囲。このメカニズムは、シングルスレッド環境の実現に非常に簡単です、しかし、マルチスレッド環境でのリスクがあります。この記事では、慣性ローディング機構とマルチスレッド環境での使用に焦点を当てています。(著のnumberzero、IBMの記事「ダブルチェックロックとSingletonパターン」、転載することを歓迎し、議論を参照してください)

1、ロード不活性シングルトン
我々はシングルトンクラスを設計するとき、クラス内、およびへのアクセスを提供する静的getInstanceメソッド外クラス(コンストラクタ、または直接に定義された作成)を構築します。通常方法シングルトンオブジェクト。例えば:

コードをコピー
コードをコピー
パブリッククラスシングルトン         
{         
    プライベート静的シングルトンインスタンス=新しいシングルトン()。        
    プライベートシングルトン(){         
        ...         
    }         
    パブリック静的シングルトンのgetInstance(){         
             インスタンスを返します。         
    }         
}
コードをコピー
コードをコピー

私たちは、このインスタンスの時間を必要としないかもしれないときに最初にロードクラスでもシングルトンインスタンスを使用して作成され、そのような結果と我々は異なる期待するためのインスタンスを作成します。欠点は、このコードはということです。そして、この場合には、システムリソースを消費するシングルトンインスタンスを作成し、常にシングルトンインスタンスを使用していないアプリケーションは、シングルトンで消費されるシステムリソースの作成が無駄にされました。

これを避けるために、我々は通常時にのみ使用されて作成しようとしている遅延ロード・メカニズムを使用します。次のように遅延ロード上記のコードのコードです。

コードをコピー
コードをコピー
パブリッククラスシングルトン{         
    プライベート静的シングルトンインスタンス= NULL;        
    プライベートシングルトン(){         
        ...         
    }         
    パブリック静的シングルトンのgetInstance(){         
        IF(例えば== NULL)         
            インスタンス=新しいシングルトン()。         
                インスタンスを返します。         
    }         
}       
コードをコピー
コードをコピー

図2に示すように、遅延ロードのマルチスレッドの問題
:抽出された第1のコードをロードされた不活性   

パブリック静的シングルトンのgetInstance(){         
    IF(例えば== NULL)         
    インスタンス=新しいシングルトン()。         
    インスタンスを返します。         
}      

 二つのスレッドAとBが同時にメソッドが実行され、その後、次のように行わ場合には、次のとおりです。

1.判決fooがnullのときににあれば、入力された場合

2. Bが入力した場合、FOOもヌルであるので、次にAは、FOOを作成されていない、及びBも入る従ってかどうかを決定します

3. Aは、fooとリターンを作成します

4. Bはまた、fooとリターンを作成します

この時点で、問題は、私たちが期待したものではありませんこれは、私たちのシングルトンが二回作成され、発生します。

3つのソリューションとその問題
3.1クラスのロック機構
上の問題のほとんど直感的な解決策は一つだけ呼び出す準備ができてgetInstanceメソッドを可能にしたgetInstanceプレフィックスを、同期させるための方法を追加することです:

パブリック静的同期シングルトンのgetInstance(){         
    IF(例えば== NULL)         
    インスタンス=新しいシングルトン()。         
    インスタンスを返します。         
}       

    このような解決策は確かにエラーの発生を防ぐことができますが、それは非常にパフォーマンスに影響を与えている:シングルトンがロックを取得する必要がありgetInstanceメソッドへの各呼び出しは、実際には、インスタンスが作成された単一の場合の後、後続の要求は必要ありませんその後、相互排他メカニズムを使用します

3.2ダブルチェックロッキング
一度誰か上記の問題を解決するために、ダブルチェックロッキング・ソリューションを

コードをコピー
コードをコピー
パブリック静的シングルトンのgetInstance(){         
    IF(例えば== NULL)         
        同期(インスタンス){         
            IF(例えば== NULL)         
                インスタンス=新しいシングルトン()。        
        }         
    インスタンスを返します。         
}
コードをコピー
コードをコピー

 のは、このコードがどのように機能するかを見てみましょう。まず、スレッドが要求を出したときに、それが最初のようにそれが取る同期ブロックにリソースを避けて、その内容に戻り、直接そのインスタンスがnullであるかどうかをチェックし、もしません。第二に、偶数セクション2に記載されている場合、裁判官が、それらはまたためにコードの同期ブロックを実行しなければならない場合は、コードの最初のスレッドブロックが、新しいエントリを作成する最初に、二つのスレッドを発生場合、彼らは追加のインスタンスを作成せず、判断を渡すことはできませんので、シングルトンインスタンス、およびそれ以降のスレッドがあります。

         上記の説明は、すべて私たちの問題を解決しているようだが、実際には、ビューのJVMの観点から、コードはまだエラーが発生する可能性があります。

         JVMの場合は、1つのJava命令を実行しています。Javaの命令でオブジェクトと代入演算子を作成するには、そのインスタンス=新しいシングルトン()、別々に行われ、文は二つのステップで実行されます。しかし、JVMは、シングルトンインスタンスを初期化するために行く、新しいJVMインスタンスが存在する可能性があることを意味シングルトンはスペースを割り当てる、これら二つの動作の順序を保証し、その後、直接割り当てられたインスタンスメンバはありません。これは、できるだけミスをします、我々はまだA、B二つのスレッド、例えば:

最初かどうかを決定するには1. A、Bのスレッド

2. Aは、最初のインスタンスがヌルであるため、それがインスタンス=新しいシングルトン()を実行し、同期ブロックに入ります。

3. JVM、第1の延伸ブランクメモリシングルトンインスタンスに割り当てられ、メンバーインスタンスに割り当てられたJVM番号内部最適化機構ので(この場合は、初期化JVMこの例を開始しないことに注意)、その後同期ブロックを残しました。

4. Bは、この時間インスタンスがnullではないので、それは直ちに同期ブロックを左に、同期ブロックに入り、メソッドを呼び出したプログラムに結果を返します。

このとき5.スレッドBシングルトンインスタンスが使用することを意図したが、それは、初期化されていないエラーが発生していることがわかりました。

マルチスレッド環境でシングルトンが内部4クラスによって実現され
、ロードに時間がかかる達成するために、すべての時間のgetInstance呼び出し相互に排他的で実行する必要はしたくない、最良かつ最も便利なソリューションは、次のとおりです。

コードをコピー
コードをコピー
パブリッククラスシングルトン{         
    プライベートシングルトン(){         
        ...         
    }         
    プライベート静的クラスSingletonContainer {         
        プライベート静的シングルトンインスタンス=新しいシングルトン()。        
    }         
    パブリック静的シングルトンのgetInstance(){         
        SingletonContainer.instanceを返します。        
    }         
}   
コードをコピー
コードをコピー

     JVM内部機構は、クラスがロードされたとき、このクラスのロード処理が相互に排他的スレッドであることを保証します。だから我々は最初のgetInstanceを呼び出すときに、JVMは、そのインスタンスを確実に私たちを助けることができることを一度だけ作成され、インスタンスに割り当てられたメモリが初期化されていることを確認しますので、我々は3.2を心配しないでください。また、この方法は、最初の呼び出しの際に相互排他メカニズムを使用しますが、これは3.1の非効率性を解決します。あなたの最初のロードSingletonContainerクラス、およびSingletonContainerクラスはgetInstanceメソッドを呼び出すときにのみロードされ、したがって、遅延ロードを達成したときの最後のインスタンスが作成されます。

おすすめ

転載: www.cnblogs.com/zyy1688/p/11077142.html