Javaの並行 - 通知とJava並行処理の間にスレッドが待機する - 合わせたCountDownLatch源、セマフォソースコード、ソースコードビューAQS原理のReentrantLockの

はじめに:

  スレッド間の協力があり、いくつかの並行プログラミングの原則の前に終了し、今、私たちは学ばなければなりません。人気の、それは待つために、現在のスレッド一定の条件の下で、あまりにも多くのシステムリソースを使用しないことです。一定の条件の下で、我々はそれが動作し続け、それはシステムリソースに割り当てる必要があり、それをウェイクアップする必要があります。これは、より良いリソースを節約します。

、オブジェクトの待機()と通知()

  基本的な概念:

    スレッドが条件付き実行ターゲット・アクションはターゲットアクションを満たすために中断されるための要件待っている、とスレッドの条件付き実行を満たすために失敗したため、スレッドを通知した後に中断されて目を覚まします。

  基本的なテンプレート:

同期(OBJ){
             // 保護条件が満たされていない
            一方で(フラグ){
                 // 現在のスレッドを一時停止
                )(obj.waitします。
            }
            // 保護条件が満たされたとき、それは外whileループが目標アクション実行である
            )のdoActionを(。
        }

  待機の解析():はObject.wait()の役割は、実行のスレッドが実行ライフサイクルのスレッドは、それがどこにあるかに注意を払う、WAITINGを変更するには、中断されていることを確認することで無期限に待機する通知()メソッドは、スレッドが起動通知まで。役割はObject.wait(長いタイムアウトが)され、自動的にウェイクアップウェイクアップされていない一定の時間にわたって実行スレッドで待機してタイムアウトになりましたObject.wait(長いタイムアウトが、naous INT)時間を制御するより正確な方法であるが、それはナノ秒に制御することができます。現在のスレッドが待ち状態、他のスレッドにスレッドが現在のロックを取得しようとするように、ロックが持つメソッドと、現在のスレッドのリリースを実行しなければならないときの待機()がロックされることに留意すべきです。ロックを適用し、ロックを解除するために必要とされます。

  通知()の解析: Object.notify()メソッドは、モーニングコールは、()のスレッドを待つことであるだけウェイクまで複数のスレッドがある場合は、スレッドは、我々が望むものを目を覚ますことができない場合があります。Object.notifyAll()は、すべての待機中のスレッドをウェイクアップします。最初のロックに通知スレッドを取得する必要があります通知方法を通知します。現在の通知スレッドを通知した後にロックを解除する必要があり、その後、待機中のスレッドによって獲得。だから、ステップは、ロックを適用することを含む、ロックを解除します。

  待ち時間)(間の3つの問題()と通知:

  上記の分析から見ることができ、ウェイク通知()(、のnotifyAll無指向性である)公平きっかけです。したがって、次の3つの質問を生成します

  早期ウェイク:、スレッドN1更新条件とウェイクによって(W1、W2、W3)通知する(N1、N2、N3)オブジェクトOBJ上のスレッド同期、W1、W2決意同じウェイクアップ状態、現在の三つのグループが待機W3と仮定する異なる判断はN2、N3更新条件によって条件を、目を覚ますと目を覚まし、N1行っウェイクアップは、あなたが実行できないならば、通知し、2つのスレッドが唯一のnotifyAll()を使用することができますので、目を覚ますする必要がありますが、W3後の状態でウェイクアップ会いすることができませんでした、私たちがする必要があるリソースタイアップを実行するために待っているのを。

  信号損失:この問題は、問題のプログラマのプログラミングで、問題が発生する内部機構が実現されていません。通知()を使用して、使用するのnotifyAllでのローカル番組が()あなただけのスレッドを覚ますことができれば、他のスレッドのウェイクアップ起こされることができなかったので、これは信号損失です。あなたが最初の条件は、保護を確立するかどうかを決定することなく、スレッド待ち()メソッドを実行する前に待機している場合、この通知スレッド待機しているスレッドが待ちに共有変数を更新したクリティカルセクションに入ると、通知()メソッドを実行しますが、原因の前に、表示されます。 ()も実行に失敗し、裁判官は共有変数を設定しなかった、それは待機を実行します()メソッドは、スレッドが待機状態になっている原因は、我々は信号を失いました。

  欺瞞ウェイク:。特に低いの発生確率が、オペレーティング・システムはこの現象が発生することができるようにすることですが、待機中のスレッドは、必ずしも、目を覚ますために()/のnotifyAll()を通知していません

  コンテキストの切り替えの問題は:まず、待って()は、少なくとも適用し、ロックの内側に対応するオブジェクトを解放するスレッドが発生します。ロック内部()/のnotifyAll()を通知する際に保持する必要があり、対応するオブジェクトがロックを解放する、が存在するであろうコンテキストスイッチは問題がない状態RUNNABLEの状態からRUNNABLE発生実際に

  問題のソリューション:

  ウェイクアップ信号損失や、虚偽の質問を:書かれたように、テンプレートの上にある、避けるためにwhileループを使用することができます。

  問題を切り替えるコンテキスト:代わりのnotifyAllの(プログラムの正しさを保証することで通知を使用して)()、ウェイクアップが発生することはありませ通知し、コンテキストスイッチが低減されます。そして、使用は待ち時間は()より高速なロックにも適用できるように、適切な内部ロックは、できるだけ早くリリースされる通知する必要があります。

  あまりにも早く目を覚ます: java.util.concurrent.locks.Conditionの使用は、信号を待っています。

  PS:待機の対象となるとC ++を書きネイティブメソッドを使用して通知し、ソースコードはここでは解決されません。

二、のawait()と信号(での条件)

  この方法は、各条件の内側上記の無指向質問の対応する変化は、私たちは、スレッド間でより柔軟な操作をすることができ、キューを維持するです。下記のソースコードを分析することにより、私たちは内部メカニズムを見てみましょう。条件は、インターフェース、内部クラスConditionObjectのAbstractQueuedSynchronizerの真の実現です。

  基本的な属性:

パブリック クラス ConditionObjectのは、実装条件、java.io.Serializableの{
         プライベート 静的 最終 長い serialVersionUIDの= 1173984872572414699Lを/ ** 状態のキューの最初のノード。* / 
        プライベート 過渡ノードfirstWaiter。
        / ** 状態のキューの最後のノード。* / 
        プライベート 過渡ノードlastWaiter。
}

  これは、基本的なプロパティが両端キューに保持されてから見ることができます。

  await()分析方法:

パブリック クラス ConditionObjectのは、実装条件、java.io.Serializableのを{
  公共の 最終 ボイド(待つ)スロー例外:InterruptedExceptionを{
    // 1.判断线程是否中断
    の場合(Thread.interrupted()){                       
         スロー 新しい例外:InterruptedExceptionを();
    }
   // 2.ノード内の状態キューにスレッドとしてパッケージ 
    ノードノード= addConditionWaiter();
    // すべてのロック3リリース取得した現在のスレッド(PS:メソッドが呼び出され待つ、現在のスレッドが取得したマスト排他ロック)               
    INT savedState = fullyRelease(ノード);           
     INT interruptMode = 0 ;
   // 同期キュー(condtionキューノードは、同期キューに内側から転送された現在のスレッドは、2つの可能があるかどうかを決定する4 
   //(1)他のスレッドのコールが転送(2)現在のスレッドが中断され(checkInterruptWhileWaitingから移動する)ノードに転送)信号
ながら(!isOnSyncQueue(ノード)){      // 5.同期キュー現在のスレッドが所定の位置にない、行為ブロック LockSupport.park(この);      //スレッドが中断されるので、前記ウェイクスレッドかどうかを決定する、割り込みが発生した場合、のtransferAfterCancelledWait checkInterruptWhileWaiting内のノードに転送され、
IF(!(InterruptMode = checkInterruptWhileWaiting(ノード))= 0 ){      // これを説明によるものですスレッドが目を覚ますための方法を中断し、内部同期キューにノード、転移を転送されている ブレーク } }    // 内部同期キュー7.コールacquireQueuedが排他ロックを取得し、戻り値を取得するプロセスであっ中断されていないことを示す IF(acquireQueued(ノード、savedState)&& interruptModeを!= THROW_IE){ interruptMode = REINTERRUPT。 }    // 8で「node.nextWaiter!= NULL」ウェイク裁判官スレッドが中断または信号されます。
   //になりますスレッドノードコンディションキューおよび同期キューに代わってあり、現時点では、それまでにために目を覚ますの割り込み
のIF(!node.nextWaiter = ヌル){     // 9.クリアキャンセルノード unlinkCancelledWaiters(); }    // 「!InterruptMode = 0」10を介してウェイクアップ割り込みスレッドを表す IFを(!InterruptMode = 0 ){      // 11.型interruptModeの決定に応じて、例外をスローして、または約それらを再び割り込む reportInterruptAfterWait(interruptMode)。 }   } }

  あなたが条件キューノード同期キューから現在のスレッドがロックウェイクを競争するためにキューイングすることができます信号()メソッドを呼び出す必要がある時には、上記のソースコードは、キューがある条件のメンテナンスキュー内で見ることができます。

  信号()出典分析:

パブリック クラス ConditionObjectのは、実装条件、java.io.Serializableの{
     公共の 最終 ボイド信号を(){
             場合(!isHeldExclusively())
                 スロー 新しい)(ないIllegalMonitorStateExceptionを。
            ノード最初 = firstWaiter。
            もし(最初の!= nullの
                doSignal(最初の);
        }
    プライベート 無効doSignal(ノードファースト){
             行う{
                 // 着信ノードリストが空の場合、ブランキングテール・ノード
                IF((firstWaiter = first.nextWaiter)== nullのを
                    lastWaiter = NULL ;
                 // 次現在のノードが空である 
                first.nextWaiter = NULL ;
                 // ノードから状態キュー同期キューに成功した移行は、その後、ループを終了した場合、ノードは、ループを終了し、空です。そうでない場合、キューは、ノードのウェイクアップを見つけるために実行される 
            } ながら(!transferForSignal(最初の)&& 
                     (第!= firstWaiter)= ヌル)。
        }
} 

  任意のスレッドキューが起こされるための信号()待ちます、signalAll()は、ウェイクアップキュー内のすべてのスレッドです。別のキューを使用して、異なるスレッドのようなメンテナンスは、あなたは、指向機能を実現することができます。これは、資源の枯渇をもたらし、早期ウェイクアップすることによって排除することができます。必要にコンテキストスイッチの損失を回避するために信号()メソッドロック、すなわちロック()、次に必要が迅速(ロック解除する)、使用前に得ることがあることに注意してください。

要約:

  オブジェクト指向の世界では、カテゴリは、多くの場合、計算を完了するために一緒に他のクラスの助けを必要とし、同じスレッドの世界には、タスクが起床待ち完成させることができると同時に、優れた操作スレッドで、複数のスレッドで、そのスレッドので、あなたが他のスレッド操作にリソースを与えることができたときに、リソースを使用せずに、そこにリソースを割り当てる際に、リソースを使用する必要があります。同期キューは、参照条件に挙げることができるJavaの並行処理-組み合わせたCountDownLatchソース、AQS原理セマフォのソースコードとソースコードビューのReentrantLockの内部キューを維持探すためにどのようにロックを取得することです。

おすすめ

転載: www.cnblogs.com/Cubemen/p/11691336.html