免責事項:この記事は「風と雨をランティング」CSDNブロガーのオリジナルの記事で、CC 4.0 BY-SAの著作権契約書に従って、再現し、元のソースのリンクと、この文を添付してください。
オリジナルリンクします。https://blog.csdn.net/ns_code/article/details/17229601
通知を待っている間にスレッドが受信されていますが、状態は、スレッド、この待ち時間を満たさない場合、スレッドは条件が短時間に満たされた場合、早期の通知を受けなかったが、すぐに変更され、もはや会うれ、その後、早期の通知が発生します。これは奇妙な現象、プログラムを通じて問題を説明するには、次の例に聞こえます。
程度別のスレッドがそれにアイテムを追加しながら、非常に単純な、2つのスレッドが待機は、リスト内の要素を削除します。コードは以下の通りであります:
パッケージcom.itheima.gan; インポートjava.util.Collections; インポートjava.util.LinkedList; インポートはjava.util.List; パブリック クラス EarlyNotify 拡張オブジェクト{ //がのプライベートコレクションの作成 プライベート一覧リスト; // コンストラクタ パブリックEarlyNotify(){ 一覧 = Collections.synchronizedList(新しい新しいLinkedListの()); } // 出力方法 プライベート 静的 無効印刷(文字列MSG){ 文字列名 = にThread.currentThread()のgetName(); のSystem.out.println(名 + "" +MSG); } // 削除要素法 パブリック文字列removeItem()はスローInterruptedExceptionある{ 印刷(「RemoveItemメソッドにスレッドを」); 同期(リスト){ // コレクション要素は、上で空のスレッドが待機であれば IF (list.isEmpty ()){ 印刷は、(「コレクションが空である、waitメソッドを開始した」); / * 実行待ちのスレッド、ロックが開催されたときに解放されますが、 *ロックを競争するために継続して行く前に、メソッドに通知したり、目を覚ますnotiffyAllまで * * / list.wait(); 印刷( "waitメソッドのうち、目を覚ます" ); } 最初の要素を削除します// 項目=文字列(String)をlist.remove(0 ); 印刷( "終了RemoveItemメソッド" ); 戻り値の項目; } } // メソッドの追加 公共 のボイドのaddItem(文字列の項目){ 印刷( "入力されたAddItemメソッドを" ); 同期(リスト){ // 追加要素が List.add(項目); プリント(「添加方法、添加元素を入力」); // 添加後、ウェイクアップ方法の実装 list.notifyAll(); プリント(「実行ウェークアップ方法" ); } 印刷("AddItemメソッドを終了" ); } 公共の 静的な 無効メイン(文字列[]引数を){ // オブジェクト作成 最終 EarlyNotify ENが= 新しい新しいEarlyNotifyを(); // スレッド削除 のRunnableルナ= 新しい新規のRunnableを(){ @Overrideの 公共 ボイドラン(){ 試み{ //は、削除処理を実行し、除去要素戻り 列アイテム= en.removeItemを(); プリント(「runメソッドへの要素の削除返す」+ アイテム); } キャッチ(InterruptedExceptionあるE ){ e.printStackTrace(); } キャッチ(例外e){ e.printStackTrace(); } } }。 // 添加线程 RunnableをrunB = 新しいRunnableを(){ @Override 公共 のボイドの実行(){ en.addItem( "こんにちは!" )。 } }。 試す{ スレッドthreadA1 = 新しいスレッド(ルナ、 "删除线程1" )。 threadA1.start(); Thread.sleep( 500 )。 スレッドthreadA2= 新しいスレッド(ルナ、 "删除线程2" ); threadA2.start(); Thread.sleep( 500 )。 thread3スレッド = 新しいスレッドを(runB、 "添加线程" ); thread3.start(); Thread.sleep( 10000 ); threadA1.interrupt(); threadA2.interrupt(); } キャッチ(InterruptedExceptionある電子){ // TODO自動生成されたcatchブロック e.printStackTrace(); } } }
結果:
分析:removeItemでまずスタートthreadA1、threadA1コール待ち()()内のオブジェクトのリスト上のロックを解除します。数500msのでは、threadA2、threadA2コールremoveItem()を起動し、オブジェクトリストのロックを解除し、待機中ので()メソッドの詰まり、またリストが空であることが判明し、リスト上のオブジェクトのロックを取得します。別の500msの後、threadBを起動し、のaddItemを呼び出して、ターゲットリストのロックを取得し、リスト内の要素を追加、のnotifyAllを持つすべてのスレッドに通知します。
threadA1とthreadA2()ターゲットリストオブジェクトのロックを取得して、成功するための操作を1つだけ問題があるだろう、リストから追加された要素を削除しようとするのを待って、待機から返されます。threadA1は、リスト上のオブジェクトのロックを取得し、成功の削除要素あなたがsynchronizedブロックを終了すると、それはターゲットリストのロックを解除すると仮定し、リスト上のオブジェクトのロックを取得しますthreadA2この時間は、のリストを削除していきます要素が、リストはすでに空であり、これははIndexOutOfBoundsExceptionをスローします。
これらの問題を回避するには、単にリストが空の場合、スレッドが待機していきますが、コードは、要素のリストを削除し、実行していきませんので、。、ループ中に変更することができますif文の周囲を待ちます
要約:/通知機構は、一般的にスレッド待ち()メソッドのループは、条件が満たされている間待機使用コールに必要とされるだけブール変数の一般的な使用とそうも、whileループを終了する(または他の真を判断することができるように条件は実装コードの後ろに、ループwhileループの外に満たさない場合、偽の条件、本明細書list.isEmpty())は、whileループにwhileループの条件は、待機()メソッドが実行されます。