1.定義
- 配信対象(公開):オブジェクトが現在の範囲外のコードで使用することができる作ります
- オブジェクトの脱出(エスケープ): falseをリリース。オブジェクトがまだ構築されていない場合は、他のスレッドで見られます
2.問題
右のリリースは、2つのオブジェクトで問題が発生しました:
(1)基準自体は、他のスレッドから見えることを特徴とします。
他のスレッドから見える対象物の状態(2)。
PSは:何の共有オブジェクトが存在しない場合は、そんなに簡単に、しかし、マルチスレッドの書き込みにあるため、マルチスレッドプログラミングでは、まず第一の原則は、共有オブジェクトを避けるためですあなたがオブジェクトを共有したい場合は、コンストラクタの右側に加えて、正確に書くだけでなく、非常に重要な問題の権利を公開する方法。
パブリック クラスクライアント{ パブリックホルダーホルダー。 公共 ボイド初期化(){ ホルダー = 新しいホルダー(42 )。//这个代码不是原子的 } } パブリック クラスホルダー{ INT N。 パブリックホルダー(int型N){ この .N = N。 } 公共 ボイドassertSanity(){ 場合(N =!N) スロー 新しい( "この文は偽である。" AssertionErrorがします)。 } } / ** Clientクラスでは、ホルダーオブジェクトが解放されるが、これは正しくないリリースです。可視性の問題のため、他のスレッドでも、右、すでに構築された不変条件でのオブジェクトの構造関数の構成では、これは参照するには、他のスレッドが作成されていない間違ったリリースにつながる、矛盾した状態でホルダーオブジェクトを見ることができます完成したオブジェクト。主な目的は、ホルダーがアトミックではありません作成することで構築されていない可能性があり、他のスレッドは、ホルダーオブジェクトを呼ぶようになりました。 したがって、ホルダー・オブジェクト(オブジェクトの状態が参照が含まれておりません)他のスレッドから見える、それを確実にするので何の同期方法が正しく未発表ホルダーなりません。ホルダーは、問題そのものではないが、それが適切に解放されません。問題は、右の解放しません上記につながる可能性があります (それ自体を参照するフィールドの別のスレッドホルダーを、あなたは(ホルダーがセットされている場合でも)、null参照につながる古い値、または古い値が表示されることがありますではありません)他のスレッドを参照してください
もっと恐ろしいですそれが更新参考文献を参照するための時間に、ホルダーのために更新されていますが、オブジェクトの状態のために、あなたは上記のコードの古い値が例外をスローすることが可能性が高いことがわかりますAssertionErrorが
主ホルダ=新しいホルダー(42)の構成が完了していない場合、このコードができない原子、別のスレッドホルダーオブジェクト参照は、予期しない結果につながる、呼び出されます。 * /
3. 施工プロセス安全目標
(1)オブジェクトの構築時には、この基準を公開していません
パブリック クラスのEventListener { 公共のEventListener(のEventSourceのEventSource){ // 私たちの初期化を行う... // イベントソースで自分自身を登録し eventSource.registerListener(この); } 公共のonEvent(イベントe){ // イベントを処理} } パブリック クラス RecordingEventListenerが延びたEventListener { 民間 最終ArrayListのリストを、 公共RecordingEventListener(のEventSourceのEventSource){ スーパー(のEventSource)。 リスト= Collections.synchronizedList(新しいArrayListを())。 } 公共のonEvent(イベントe){ list.add(E); スーパー.onEvent(E); } パブリックイベント[] getEvents(){ リターン(イベント[])list.toArray(新しいイベント[0 ])。 } }
あなたは、コンストラクタで内部クラスを作成する場合は、解放コンストラクタで彼を置くことができない、コンストラクタの外に公開されるべきであり、そのためには、コンストラクタであるが終了し、初期化が完了した後、内部クラスを解放されています。
(2)暗黙的に「this」参照を公開しないでください。
パブリック クラスEventListener2 { 公共EventListener2(のEventSourceのEventSource){eventSource.registerListener( 新しい新規のEventListener A(){ 公共のonEvent(イベントE){ eventReceived(E); } }); } 公共eventReceived(イベントE)は{} } また、サブクラスであります問題
(3)コンストラクタの中からスレッドが起動しないでください
a)のコンストラクタでスレッドを開始、コンストラクタはまだ終わっていない持って、このオブジェクトはすでに完全に構築されていることを保証するものではありません
bがスレッドでこのオブジェクトへのアクセスが開始した場合、あなたはへのアクセスを保証することはできません)構造は完全に良い物です
3. セキュリティは、コモン・モードを発行しました
オブジェクトの解放を確保するために、オブジェクト参照とオブジェクトの状態は、他のスレッドに可視でなければなりません。通常、適切に構築されたオブジェクト(これはエスケープコンストラクタを発生しない)正しくによって公開することができます。
(1)静的初期化子で参照されるオブジェクトを初期化します
(2)基準オブジェクトは、オブジェクトフィールドまたはAtomicReferenceの揮発性タイプに格納されます。
(3)ドメイン内のオブジェクトの適切に構成されたオブジェクトの最終タイプの参照を保存します。
(4)ロックによって保護ドメインへのオブジェクト参照を保存
/ ** (1)Javaで3つのオブジェクトがあり そのままA):オブジェクトの状態が作成後に変更することはできません、すべてのドメインオブジェクトは最終的なもので、オブジェクトが適切に構築された B)を本質的に同じ主題である:いない不変オブジェクト制約は、しかし、初期化後に変更されない 不変オブジェクトは、上記の制約を満足しないと本質的に同じオブジェクトが:C)可変オブジェクト (2)セキュリティ技術解放 a)はその状態を確保し、他のスレッド適切に可視の参照オブジェクト B)の方法を オブジェクト参照を初期化するための静的初期化子は、 揮発性の記憶領域を参照する オブジェクトを作成するために、正しい最終のドメインへの参照を格納するために 適切に保護されたロックによってドメインにストア参照を (3)公開オブジェクトセキュリティの三種類 )不変オブジェクトを:機構の任意の形態を公表 b)は、実質的に同一のターゲットである:安全のリリースを確認するために )変更可能なオブジェクトをCを:安全な解放を確保するために、ほかのオブジェクト(すなわち、ロックまたは他の手段の状態を変更する権利を確保するために、正しい変更オブジェクトの状態を確保するためだけではなく) * * /
4.コンテナのセキュリティリリースを確保
同期は、スレッドセーフなコンテナ内であることを意味し、このようなベクターとして、コンテナ内の場所オブジェクトは、上記の最後の要件を満たしています。次に、オブジェクト、スレッドセーフな容器にXおよびBスレッド場合、スレッドは、我々は、これが読み取り/書き込みアプリケーションコードがXなしであっても、そのBを確保することができる状態はXのセットを見ていることを確認することができ、オブジェクトを読み出しますこれは、同期表示を含んでいます。下の容器の保証安全な解放を提供します。
(1)のHashtable、synchronizedMapかのConcurrentMapにキーまたは値によって、あなたはこれらのコンテナからアクセスするために、任意のセキュリティスレッドに公開することができます。
(2)ベクター、CopyOnWriteArrayListと、CopyOnWriteArraySet、synchroizedListを確定する要素は、これらの容器からの要素にアクセスする任意のスレッドに要素の解放を確保することができます。
(3)BlockingQueueのかConcrrentLinkedQueueへの要素によって、あなたはこれらの訪問キューから要素にアクセスするために、任意のスレッドに要素の解放を確保することができます。
5.サプリメント
一般的に、静的オブジェクトを発行するように構成され、最も簡単で安全な方法は、静的初期化子を使用することである: パブリック 静的ホルダー= 新しい新しいホルダー(42)。
静的初期化は、内部同期メカニズムのJVMに、JVMクラス初期化フェーズが実行するので、このアプローチは、オブジェクトが安全に放出することができる初期化することです。
可変オブジェクトの場合、出版物の時間は、安全性を保証するために发布当时
可視状態を、各後続の訪問目的で、また、視認性の動作を変更確実にするために同期化を使用する必要があります。(+同期状態の可視性)