あなたがロックvolatileフィールドの使用、それをダブルチェックしたい理由を知っていますか?

ダブルロックの起源

シングルモードの実施例では、DCLは(ダブルロック)の実装を持っています。Javaプログラムでは、時にはあなたは、オブジェクトの初期化動作の高オーバーヘッドの一部を延期する必要があり、そしてこれらのオブジェクトは初期化を開始する場合にのみ。

以下の非コード化された遅延オブジェクト初期化スレッドセーフの例。

インタビュアー:なぜ二重のチェックがvolatileフィールドをロックでしょうか?


UnsafeLazyInitializationクラスで、コードA 1の実行スレッドを同時に仮定され、B 2スレッドは、コードを実行します。この時点で、スレッドが終了していないオブジェクトインスタンスの初期化への参照が表示される場合があります。

UnsafeLazyInitializationクラスのために、我々は怠惰な初期化スレッドセーフのgetInstance()メソッドに同期やって実装することができます。

次のようにサンプルコードがあります。

インタビュアー:なぜ二重のチェックがvolatileフィールドをロックでしょうか?


同期プロセスを行うためのgetInstance()メソッドのため、同期パフォーマンスのオーバーヘッドにつながります。getInstance()メソッドは、頻繁に複数のスレッドを起動された場合は、プログラムの実行性能低下につながります。

getInstance()メソッドは、複数のスレッドによって頻繁に呼び出されない場合は逆に、次いで、遅延初期化プログラムは、十分な性能を提供するであろう。

その後、彼は提案した「スマート」ヒント:ダブルチェックロック(ロックをダブルチェック)。私はダブルチェックロックすることにより、同期のオーバーヘッドを削減したいです。

以下のコード例は、遅延の初期化ダブルチェックロックを使用して達成されます。

インタビュアー:なぜ二重のチェックがvolatileフィールドをロックでしょうか?


ダブルチェックロックは完璧なようだが、これは間違って最適化です!

コード読取りインスタンスがnullでない実行する最初のスレッドでは、オブジェクト参照のインスタンスが初期化を完了することができませんでした。

問題の根

ロックされたコード(例えば=新しいインスタンス();)の第4の例を前述の二重チェックは、オブジェクトを作成します。このコード行は、以下の擬似コード3行に分割することができます。

インタビュアー:なぜ二重のチェックがvolatileフィールドをロックでしょうか?


擬似コード2及び3の上部3行との間には、並べ替えてもよい(このリオーダリングが発生し、いくつかのJITコンパイラでも同様である)、以下のように2と3の間に再配列のその後の実行タイミング:

インタビュアー:なぜ二重のチェックがvolatileフィールドをロックでしょうか?


マルチスレッド実行タイミングテーブル

  • T1 A1:メモリの割り当て

  • T2 A3:セットポイントメモリインスタンス

  • T3のB1:インスタンスが空であるかどうかを決定します

  • T4のB2:インスタンスがnullでないため、スレッドBは、オブジェクトインスタンスの参照にアクセスします

  • T5 A2:オブジェクトを初期化します

  • T6 A4:オブジェクトインスタンスの参照へのアクセス

後に問題のある出来事のルートを知っている、我々は怠惰な初期化スレッドセーフを実現するための2つの方法を考えることができます。

1) 2と3の並べ替えはできません2)並べ替え2と3ができますが、「見る」、この並べ替えに他のスレッドを許可していません。

両方の溶液は、上記の二つの点に対応する、後述します。

Aソリューション

ベースの揮発性ソリューション

インタビュアー:なぜ二重のチェックがvolatileフィールドをロックでしょうか?


注:このソリューションは、バージョンJDK5または(JDK5から新しいJSR-133仕様のメモリ・モデルを使用して起動するので、この仕様は、揮発性のセマンティクスを増強する)を必要とします。

オブジェクトがマルチスレッド環境で、行3,2、擬似コード3との間の参照揮発性、再順序付けの後に宣言されたときには、禁止されます。

ソリューション2

初期化のためのクラスベースのソリューション

(すなわち、クラスがロードされる前に、スレッド)JVMのクラスの初期化フェーズは、初期クラスを実行します。

初期化の実行クラスの間に、JVMは、ロックを取得することになります。ロックは、同じクラスを初期化するために複数のスレッドを同期することができます。

この機能に基づいて、別のスレッドセーフな遅延初期化プログラム(このプログラムは、初期設定オンデマンド・ホルダーイディオムと呼ばれる)を達成することができます。

インタビュアー:なぜ二重のチェックがvolatileフィールドをロックでしょうか?


フィールドの初期化遅延は、クラスのインスタンスを作成したり、初期化のコストを削減するが、アクセスのコストは、遅延初期化フィールドで増加します。

通常の初期化遅延初期化よりも優れ、ほとんどの時間。あなたがスレッドセーフ使用してインスタンスフィールドを初期化するために遅延が必要な場合は、揮発性の溶液の遅延初期化に基づいて、上記の説明を使用しています。あなたは本当にスレッドセーフは、クラスベースの初期化スキーム上記の説明を使用して使用して静的フィールドを初期化するために遅延が必要な場合。

弟の感触が良いのエッセイは、それに集中するポイントを与えるより徐々にそれを与えます。

最後に、JVM、ロック、並行性の高い、反射、春の原理、マイクロサービス、飼育係、データベース、データ構造、およびその上を覆って、面接の本「.PDFを終えたJavaコア知識」を共有しています。私の個人的なファンベースに追加する(Javaのテクノロジー・スタックアーキテクチャ:644 872 653)を受信するための無料の方法のために。


おすすめ

転載: blog.51cto.com/14480698/2458428