2011-03-02 12 views
2

Javaの並行性に関する私の記憶をリフレッシュしていて、普及しているプロデューサのコンシューマの問題で遊んでいました。私は、単一のプロデューサーと単一のコンシューマーが存在する場合、正しく動作する以下のコードを実装しました。ただし、複数のプロデューサ/コンシューマが存在する場合、正しく機能しません。それ以外の場合は、いくつかのスレッドが目を覚ますと、条件がまだ満たされていない時に継続することができJavaの複数のプロデューサとコンシューマの問題(BlockingQueueなし)

while(condition not met) 
    wait(); 

public class ProducerConsumer { 

    static Monitor monitor; 

    public ProducerConsumer(int maxSize) 
    { 
     monitor = new Monitor(maxSize); 
     new Producer().start(); 
     new Producer().start(); 
     new Consumer().start(); 
     new Consumer().start(); 
    } 

    class Producer extends Thread{ 

     @Override 
     public void run() { 
      while(true) 
      { 
       try { 
        monitor.insert(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 

    class Consumer extends Thread{ 

     @Override 
     public void run() { 
      while(true) 
      { 
       try { 
        monitor.remove(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 

    class Monitor { 

      int n; 
      int maxSize; 

     public Monitor(int maxSize) 
     { 
      n=0; 
      this.maxSize = maxSize; 
     } 

     synchronized void insert() throws InterruptedException 
     { 
      if(n==maxSize) 
       wait(); 
      System.out.println("Producer: "+n++); 
      if(n==1) 
       notifyAll(); 
     } 

     synchronized void remove() throws InterruptedException 
     { 
      if(n==0) 
       wait(); 
      System.out.println("Consumer: "+n--); 
      if(n==maxSize-1) 
       notifyAll(); 
     } 
    } 

    public static void main(String[] args) { 
     ProducerConsumer pc = new ProducerConsumer(100); 

    } 
} 

答えて

8

wait()は、常に次のように使用しなければならない理由を私は見ることができません。限られたリソースがすでにによって排出されるとき

  1. あなたがnotifyAll()を呼び出すと、あなたがすべての待機中のスレッドを覚まし、条件が再び偽であるときにそれらのいくつかは、手遅れになるように(つまり、このような状況のための2つの理由が考えられます他のスレッド)。
  2. 偽のウェークアップ(スレッドに対応するnotifyなしのウェークアップ)が発生する可能性があります。

あなたが実際に一つだけのスレッドをウェイクアップする必要がある場合は、代わりにnotifyAll()notify()を使用することができます。最初の問題は解消されますが、依然として偽のウェークアップから保護することはできませんので、まだwhileが必要です。

+0

I second(パッド+1) – ant

+0

ありがとうございました。しかし、スレッドが既に存在する場合、synchronizedメソッドはスレッドにそれを入力させることはできないと考えました。このコンセプトについて私が誤解したことは、この動作につながったのですか? – 3ashmawy

+1

@ 3ashmawy:はい、スレッドが 'wait()'を呼び出すとロックを解除します。後続の 'notifyAll()'の起動後にスレッドが待ち行列に入り、ロックを再度取得して 'wait()'の後に続行します。明らかに、そのキュー内の最初のスレッドは状態を変更し、最後のスレッドは条件が再び満たされないことを検出します。 – axtavt

関連する問題