Javaはスレッド--notifyAll通知を漏洩しました

免責事項:この記事は「風と雨をランティング」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ループの条件は、待機()メソッドが実行されます。

おすすめ

転載: www.cnblogs.com/zhilili/p/11969832.html