2016-08-19 19 views
4

Javaで単純な待機/通知の例を取り組んでいて、何らかの理由で正しく動作させることができませんでした。誰かが何が問題かもしれないかを見ることができれば、非常に感謝しています!Javaコードでnotify()とnotifyAll()がJavaコードで機能しない

class producer implements Runnable { 
    StringBuffer sb; 
    producer() { 
     sb=new StringBuffer(""); 
    } 

    public void run() { 
     synchronized(sb) { 
      for(int i = 0; i < 10; i++) { 
       try { 
        sb.append(i+" "); 
        System.out.println("Appending ... "); 
       } catch (Exception e) {} 
      } 
      sb.notify(); 
     } 
    } 
} 

class consumer implements Runnable { 
    producer p; 
    consumer(producer pp) { 
     this.p = pp; 
    } 

    public void run() { 
     System.out.println("Rreached"); 
     synchronized(p.sb) { 
      try { 
       p.sb.wait(); 
      } catch (Exception e) {} 
      System.out.println(p.sb); 
     } 
    } 
} 

class Thread_Comunication { 
    public static void main (String [] args) { 
     producer p = new producer(); 
     consumer c = new consumer(p); 

     Thread t1 = new Thread(p); 
     Thread t2 = new Thread(c); 
     t1.start(); 
     t2.start(); 
    } 
} 

出力:

Appending ... 
Rreached // randome Position 
Appending ... 
Appending ... 
Appending ... 
Appending ... 
Appending ... 
Appending ... 
Appending ... 
Appending ... 
Appending ... 

ので、いくつかの理由でスレッドt1t2を覚ますか、私は完全に他の何かが欠けていないのですか?

+1

、例外が発生した場合、' 'あなたのcatch'ブロックで特にあなたが知っていることは決してないだろう。だから、consumerのような何かを行うことができます。 – Jesper

+1

注:Java言語の規約では、クラス名は大文字の名前で始まります(したがって、 'producer'は良いクラス名ではありません)。クラス、メソッド、またはパッケージ名にはアンダースコアが使用されず、すべての資本定数の名前でのみ使用されます。クラスには 'ThreadCommunication'のような名前があり、' Tread_Comunication'ではありません。変数には、 'p'や 'pp'ではなく、意味のある名前を付けることもお勧めします。 – RealSkeptic

+0

投票者を閉じる:コードは少なくともスケジューラの裁量で発生する可能性のある競合状態に依存するため、投稿されたコードは問題を再現します(できるだけ多くの場合)。投稿されたコードと出力との間には、ここで何が起こっているのかを理解することが現実的です。 –

答えて

3

Notifyは、別のスレッドが待機していない限り、何もしません。コードは通知(条件変数が必要な場合)にのみ依存し、プロデューサの前に実行されているコンシューマを使用して動作します。

出力によれば、プロデューサが最初に実行されます。それは消費者が走る機会を得る前に完全に実行されます。 (消費者が実行するためには、プロデューサが保持しているsbのロックを取得する必要があります)プロデューサは通知を呼び出しますが、スレッドは待機していないため、効果はありません。それから消費者は待っていて通知が来ないので、無期限にハングします。

消費者が最初に実行される場合、コードは正常に終了します。

最初に実行するものを制御できないため、別のスレッドより先に実行されるスレッドに依存するコードを書くことは避けてください。あなたが待っているときは、条件をテストするループの内部でそれを行う必要があります。複数の理由の1つは、スレッドが待機する前に条件が設定されている場合、スレッドは待機しないことを知ることができるということです。

条件を使用するコードを変更する:

import java.io.*; 

class producer implements Runnable { 
    StringBuffer sb; 
    boolean done = false; 
    producer() { 
     sb=new StringBuffer(""); 
    } 

    public void run() { 

     synchronized(sb) { 

      for(int i=0;i<10;i++) { 
       try { 
        sb.append(i+" "); 
        System.out.println("Appending ... "); 
       } catch (Exception e) {} 
      } 
      sb.notify(); 
      done = true; 
     } 


    } 
} 

class consumer implements Runnable { 
    producer p; 
    consumer(producer pp) { 
     this.p=pp; 
    } 

    public void run() { 
     System.out.println("Rreached"); 
     synchronized(p.sb) { 
      try { 
       while (!p.done) { 
       p.sb.wait(); 
       } 
      } catch (Exception e) {} 

      System.out.println(p.sb); 
     } 
    } 
} 


public class Communication { 
    public static void main (String [] args) throws Exception { 
     producer p= new producer(); 
     consumer c= new consumer(p); 

     Thread t1= new Thread(p); 
     Thread t2= new Thread(c); 
     t2.start(); 
     t1.start(); 
    } 
} 
1

だから私は、単純な待機/ Javaでの例を知らせるに取り組んで、私はそれを正しく実行するために取得することができていない何らかの理由でされています。

コードの問題は、notify()が保持されないということです。 producerが​​ブロック最初にと入力した場合、consumerは入力して、がループを終了して終了するまでwaitになります。 notify呼び出しのすべてが​​ブロックの内が起こるので、consumerwait()になる時間によって、producerは終了していないと、もはやnotifyを呼んでいます。これは、consumerがハングしていることを意味します。

あなたがconsumer最初に起動した場合でも、あなたはまだproducerは、最初にその​​のブロックに入るために発生する可能性があります競合状態を持っている - consumerには時間がかかるSystem.out.println()を呼び出すので、これは特にそうです。 consumerはそのwait()producerロックにそれを取得するためではないが、あなたが​​呼び出しの前にThread.sleep(100)producerを遅らせる場合は、「修正」、あなたはそれが動作するようになりましたことを確認する必要があります。

これを適切に修正するには、いくつかの方法があります。通常は、consumerがチェックする必要がある別の変数であるwait/notify を使用します。あなたのケースでは、保護されているので、sb変数自体である可能性があります。少なくとも `e.printStackTrace()入れ

synchronized (p.sb) { 
    try { 
     // do we need to wait to see if the producer added stuff? 
     if (p.sb.length() == 0) { 
      p.sb.wait(); 
     } 
    } catch (InterruptedException e) { 
     // this is always a good pattern to preserve the interrupt flag 
     Thread.currentThread().interrupt(); 
     return; 
    } 
} 
関連する問題