序文
ターゲットはそれを解放とは何ですか?簡単に言えば、オブジェクトは、私たちの定義は、他の範囲の範囲外で使用することができますようにすることです。
ボディ概要
- リリースおよびオブジェクトの脱出
- ターゲットのセキュリティリリースに4つの方法
主なコンテンツ
オブジェクトの最初に、リリースおよびエスケープ
1.コンセプト
ポストオブジェクト:現在の範囲外のコードで使用できるオブジェクトを作ります。
オブジェクトのエスケープ: falseをリリース。オブジェクト構造を完了していない場合は、他のスレッドで見られます。
2.通常、我々は公共の静的変数のオブジェクトを公開するための参照の非プライベートメソッドやクラスによってオブジェクトを返します。次に、実施例を見ると非プライベートメソッドの戻りオブジェクトの危険な放出を挙げ。
SLF4J @ パブリック クラスUnsafePublish { プライベート文字列[]米国= { " A "、" B "、" C " ;} パブリック文字列[] GETSTATES(){ リターンステート; } パブリック 静的 ボイドメイン(文字列[]引数){ UnsafePublishアップ = 新しい新しいUnsafePublish(); log.info(" 状態:{} " 、Arrays.toStringの(up.getStates())); // プライベートプロパティ変更のそれは配列 up.getStates()[ 0] = " D " 。 log.info(" 状態:{} " 、Arrays.toString(up.getStates()))。 } }
このような結果は次のようになります。
23:19:37.949 [メイン] INFO com.controller.publish.UnsafePublish - 状態:[A、B、C] 23:19:37.952 [メイン] INFO com.controller.publish.UnsafePublish -状態:[D、B、 C]
私たちは、他のスレッドがないことを保証することはできないため、オブジェクトのリリースは、実際には安全ではないので例は、非常にシンプルですが、それでも見て、非プライベートメソッド(パブリックアクセスレベル)ので、外部のスレッドクラスは、このフィールドにアクセスすることができますエラーのクラス内部の状態で、その結果、このフィールドを変更します。
3.次に、例を示すように、対象についての脱出リリースをご紹介します。
SLF4J @ パブリック クラスエスケープ{ プライベート int型 thisCanbeEscape = 0 ; 公共のエスケープ(){ 新しいInnerClass(); } // 定义一个内部类 プライベート クラスInnerClass { パブリックInnerClass(){ log.info(" {} "、エスケープ。この.thisCanbeEscape)。 } } パブリック 静的 ボイドメイン(文字列[]引数){ 新しいエスケープ()。 } }
結果:
23:35:56.093 [メイン] INFO com.controller.publish.Escape - 0
パッケージのインスタンスへの参照が含まれている内部コードを見てクラスのインスタンスは、この問題が発生する可能性があり、完全に構成解除されます完了していないオブジェクトをエスケープする可能性があります。
具体的な説明:コンストラクタのエスケープで脱出を引き起こす可能性がありますスレッドを開始すると等価です工事が完了する前に、この参照のクラスのコンストラクタ内に新しいスレッドが常に被写体を見ることができますこれはへの参照です。
第二に、4つのメソッドオブジェクトの安全な解放
- 静的初期化関数の参照でオブジェクトを初期化します
- 記憶されたオブジェクトへの参照
volatile
タイプフィールドまたはAtomicReference
オブジェクト - 適切に構成されたオブジェクトに保存されたオブジェクト参照
final
タイプフィールド - ロックによって保護されたドメインへのオブジェクト参照の保存
これは、4つの方法は、それを説明するには、以下の4つの例で、それを理解する方法です。
1.まず、我々はシングルトンデザインパターンコード(怠惰な人間)マルチスレッドのシナリオで発生する問題の種類を見て通過しました。
パブリック クラスシングルトン{ // プライベートコンストラクタ プライベートシングルトン(){ } // シングルトンオブジェクト プライベート 静的シングルトンインスタンス= NULL ; // 静的ファクトリメソッド のパブリック 静的シングルトンのgetInstance(){ IF(例えば== NULL ){ インスタンス = 新しい新しいシングルトン(); } 戻りインスタンス; } }
上記観察コード、シングルスレッド、そう下マルチスレッドで問題なく、二つのスレッドインスタンス== NULL条件後裁判官は、オブジェクトを作成するプロセスに、満たされた場合、その後、プライベートコンストラクタは両側に呼び出すことと等価ですコンストラクタは、減算値のプライベートな操作である場合、この値はそれはプラスマイナス2になるではない、それは間違ってなければなりません。上記のコードは、スレッドセーフです。
見2.怠惰なシングルトン、以下のシングルトン飢えた男のスタイルを見て。
パブリック クラスSingleton2 { // プライベートコンストラクタ プライベートSingleton2(){ } // シングルトンオブジェクト プライベート 静的 Singleton2インスタンス= 新しい新しいSingleton2(); // 静的ファクトリメソッド のパブリック 静的Singleton2のgetInstance(){ 戻りインスタンス; } }
とにかく、飢えた男は、直接リソースの無駄が生じ、関係なく、オブジェクトが使用されているかどうか、それが作成されるの、パフォーマンスの問題にどのリードをクラスのオブジェクト型を作成します。私たちは空腹の男のスタイルを使用する場合したがって、我々はそれがプライベートコンストラクタ過度の処理ロジックであるかどうかを検討しなければなりません。
空腹中国風のスレッドセーフが、2つの例を要約すると、それが原因のパフォーマンスの問題に可能性があり、その後、怠惰な人間はスレッドセーフに変換することができませんか?答えはイエスです。それを変換する方法で見てみましょう!
あなたがオブジェクトを作成する方法を保証できる場合にのみ、静的なファクトリメソッドで同期加えるので、アクセススレッドセーフにスレッドによって引き起こされないであろうか、何を推測
// 静的ファクトリメソッドの パブリック同期静的Singleton3のgetInstance(){ IF(例えば== NULL ){ インスタンス = 新しい新しいSingleton3(); } 戻りインスタンス; }
この性を保証スレッドの安全性が、それはパフォーマンスコストが生じ、そのようなアプローチは推奨されません!!!
我々はオブジェクトを作成するために、同期沈むあれば?
パブリック クラスSingleton4 { // プライベートコンストラクタ プライベートSingleton4(){ } // シングルトンオブジェクト プライベート 静的 Singleton4インスタンス= NULL ; // 静的ファクトリメソッド のパブリック 静的Singleton4のgetInstance(){ IF(例えば== NULL ){ 同期( 。Singleton4 クラス){ IF(例えば== NULL ){//二重検出機構 インスタンス = 新しい新しいSingleton4()。 } } } 戻りインスタンス。 } }
実際には、このアプローチは、安全でないスレッドになっています。ここでのレビュープロセスを作成、(1)メモリオブジェクト=メモリ割り当てにだけポイントオブジェクト(3)インスタンス=メモリー設定インスタンスを初期化する(2)ctorInstance()割り当て()オブジェクトのメモリ空間を割り当てます。ここで三段階上記の結果は、上記の手順に従って行ったが、(1)になっていないJVM命令およびCPUの再発生(転位高い並行性(X)と同時に命令を参照)、(この順序で3)(2)。コードに示すように、命令の再配置を前提に、スレッドA、B識別された位置でコードを実行する各スレッド、Aは、ステップ(3)の実行を開始するとき、次いでこのシナリオでは、説明が必要発生します際の判断実行スレッドB、実測値、および戻り値のインスタンスを指示します。実際のスレッドA(2)は、オブジェクトを初期化するステップはありません。が、この問題の確率は非常に小さいですが、この方法はまだスレッドセーフではありません。
パブリック クラスSingleton4 { // プライベートコンストラクタ プライベートSingleton4(){ } // シングルトンオブジェクト プライベート 静的 Singleton4インスタンス= NULL ; // 静的ファクトリメソッド のパブリック 静的Singleton4のgetInstance(){ IF(例えば== NULL ){//スレッドB 同期(Singleton4。クラス){ IF(例えば== NULL){ // 二重検出機構 インスタンス= 新しい新 Singleton4(); //スレッドA-3 } } } 戻りインスタンス。 } }
それがあるため、命令再配置リードの問題ですので、我々はJVMとCPUの命令転位を発生させません。
揮発性:キーワードは、それを考えることを学んだ前に。添加揮発性シングルトンオブジェクトの宣言に基づいて、上記のコードに基づきます。
プライベート 揮発性の 静的 Singleton4インスタンス= nullを。
だから、怠惰な人間はシングルトンスレッドセーフになります。
通常は簡単に見過ごすことができ、コードを書くために、確かに、そこに覚えておく必要があります。揮発性+ =二重検出禁止命令並べ替えメカニズム:これは、揮発性の使用シナリオの一つです。
3.また、スレッドセーフな、信頼性の高い列挙モードで述べました:
パブリック クラスSingleton5 { プライベートSingleton5(){ } パブリック 静的のgetInstance Singleton5(){ 戻りSingleton.INSTANCE.getInstance(); } プライベート 列挙シングルトン{ INSTANCE; プライベートSingleton5シングルトン; // このメソッドが一度呼び出されることJVM絶対保証 シングルトン( ){ シングルトン = 新しい新しいSingleton5(); } 公共Singleton5のgetInstance(){ リターンシングルトン; } } }