2016-11-20 9 views
0

ProducerThreadが10までのランダムな値を生成し、ConsumerThreadがQueueの値を消費することを期待します。どこかのプロデューサが値を複数回追加しています。私は、スレッドがロックを解除し、更新を期待していたスレッドにチャンスを与えるよりも、オブジェクトに対して通知を呼び出すときにコンセプトを持っています。生産者スレッディングの消費者の誤解

ここにコードは、私の理解を修正してください。

public class ProducerThread extends Thread { 

    Queue<Integer> values; 

    ProducerThread(Queue<Integer> values) { 
     this.values = values; 
    } 

    public void run() { 
     while(true) { 
      synchronized(values) { 
       double totalValues = Math.random()*10; 
       System.out.println("Going to populate total values:" + totalValues); 

       for (int i = 1; i <= totalValues; i++) { 
        values.add(i); 
        System.out.println("Value updated: " + i); 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 
       values.notify(); 
      } 
     } 
    } 

} 



public class ConsumerThread extends Thread { 
    Queue<Integer> values; 

    ConsumerThread(Queue<Integer> values) { 
     this.values = values; 
    } 

    @Override 
    public void run() { 
     while(true) { 
      synchronized (values) { 

       try { 
        // Consumer Thread waits until values are populated by Producer Thread 
        if(values.isEmpty()) { 
         values.wait(); 
        } 

        Iterator<Integer> iterateValues = values.iterator(); 
        System.out.println("Going to consume values: " + values.size()); 
        while (iterateValues.hasNext()) { 
         Integer removedValue = iterateValues.next(); 
         System.out.println("Value deleted: " + removedValue); 
        } 
        values.clear(); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 
} 


public class Test { 
    public static void main(String[] args) { 
     Queue<Integer> values = new LinkedList<Integer>(); 
     ProducerThread producer = new ProducerThread(values); 
     ConsumerThread consumer = new ConsumerThread(values); 

     consumer.start(); 
     producer.start(); 

    } 
} 
+0

私はこれを実行し、私がそれをやるべき読んで何やっています。あなたは、あなたが期待していることを正確に明確にできますか?おそらく、サンプル出力? –

+0

@JoeCプロデューサがランダムな8の値を設定した後、プロデューサが完了すると、キューは1から8の値に設定されます。コンシューマは8つの値をすべてクリアします。次にプロデューサーはランダムな値を5に設定し、キューを1から5に設定すると、消費者のターンが来るはずです。 –

+0

2つ(またはそれ以上)のスレッドを作成するための既成の解決策はありません。なぜなら、それはスレッドのためではないからです。スレッドのグループがターンを取って行うことができるものはすべて、単一のスレッドによって効率的に実行できます。宿題が割り当てられていて、スレッドを交代させる必要がある場合は、スレッドごとに1つの 'java.util.concurrent.SynchronousQueue'を作成します。各スレッドは、キュー上で「トークン」(Object)を受け取るのを待ちます。トークンを取得すると、何らかの作業を行い、トークンを次のスレッドのキューに入れ、再び待機するように戻ります。 –

答えて

1

アハ!あなたは恐ろしい競争状態に遭遇しました!

notifyの直後にProducerThreadが返された場合、前記スレッドにはまだロックがあります。 notifyによって起動されたConsumerThreadは、ロックが利用できないことを確認し、利用可能になるまで待機します。 ProducerThreadがロックを断念

次に、それは、(waitから復帰することによって​​ブロックを再入力の仕方によってProducerThreadを、そしてConsumerThread)バックそのロックを取ることConsumerThreadでレースを入力します。これらが勝つ保証はありません。

あなたProducerThreadがより多くを生産する前に消費すべき項目を待つしたい場合は、/そのシナリオのために通知他の待ち時間を考慮する必要があります。

編集:この画像は物事を少しはっきり説明するのに役立ちます。 Wait Notify Diagram

+0

これは、別の待機と通知を使用して動作しますが、なぜProducerThreadが再びロックを取得するための競争に入ったのですか?これはProducerThreadに通知するようなものですが、ロックを解除するだけですが、待機中のスレッドには通知しません。私は待っている/ここに働いてメカニックに通知しないでください。私を修正してください。 –

+1

2つのもの。まず、 'notify'は実際にロックを放棄しません。これは、他のスレッド(この場合は 'ConsumerThread')に、それが待っていたものが今起きたことだけを通知するだけです。第2に、 'ConsumerThread'は' wait'から戻る前にロックを再取得する必要があります。 'ProducerThread'が最初に再びロックを取得した場合(ループの先頭に戻り、' synchronized'ブロックを再入力すると)、 'ConsumerThread'はブロックされたままです。 –

+0

物事を明確にするために、私の答えにダイアグラムを追加しました。 –

関連する問題