0

マルチスレッドを使用して、古典的な生産者と消費者の問題を解決しています。wait()コードでandを使用しnotifyAll()ています。私の質問はnotifyAll、他の待機中のスレッドに再開するように通知するときです。すぐには再開されません。何故ですか?コードは以下です

public class ConsumerProducer {

 private  int count;

 public synchronized void consume() {
  while (count == 0) {  // keep waiting if nothing is produced to consume
   try {
    wait(); // give up lock and wait
   } catch (InterruptedException e) {
    // keep trying
   }
  }

  count--;              // consume
  System.out.println(Thread.currentThread().getName() + " after consuming " + count);
 }

 public synchronized void produce() {
  count++;             //produce
  System.out.println(Thread.currentThread().getName() + " after producing " + count);
  notifyAll();         // notify waiting threads to resume
 }

}

クライアントコード:

public class ConsumerProducerTest implements Runnable {

 boolean isConsumer;
 ConsumerProducer cp;

 public ConsumerProducerTest(boolean isConsumer, ConsumerProducer cp) {
  this.isConsumer = isConsumer;
  this.cp = cp;
 }

 public static void main(String[] args) {
  ConsumerProducer cp = new ConsumerProducer(); //shared by both threads to communicate

  Thread producer = new Thread(new ConsumerProducerTest(false, cp));
  Thread consumer = new Thread(new ConsumerProducerTest(true, cp));

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


 }

 @Override
 public void run() {
  for (int i = 1; i <= 10; i++) {
   if (!isConsumer) {
    cp.produce();
   } else {
    cp.consume();
   }
  }

出力は次のとおりです。

Thread-1 after producing 1
Thread-1 after producing 2
Thread-1 after producing 3
Thread-1 after producing 4
Thread-1 after producing 5
Thread-1 after producing 6
Thread-1 after producing 7
Thread-1 after producing 8
Thread-1 after producing 9
Thread-1 after producing 10
Thread-2 after consuming 9
Thread-2 after consuming 8
Thread-2 after consuming 7
Thread-2 after consuming 6
Thread-2 after consuming 5
Thread-2 after consuming 4
Thread-2 after consuming 3
Thread-2 after consuming 2
Thread-2 after consuming 1
Thread-2 after consuming 0

上記の最初の行が出力された後、notifyAll が呼び出され、待機中のスレッドが再開され、printing が実行されThread-2 after consuming 0ます。私が見ている問題はThread-1 (Thread-1 after producing)、終了した後、Thread-2 が再開されることです。しかし、両方が同時に発生するはずですか?ここで私を助けてください。ありがとう編集:メインメソッド内にjoin()を持っていても、出力は変わりませんでした:

 producer.start();
  producer.join();
  consumer.start(); 
4

3 に答える 3

8

しかし、両方が同時に発生するはずですか?

ここでの問題は、生産 (および消費) にほとんど時間がかからないことです。いわゆる (重大ではない)競合状態が発生しており、プロデューサーはコンシューマーが起動する前に 10 個のアイテムすべてを生成できます。競合状態とは、この場合のバグではなく、2 つのスレッドが生成および消費するために互いに競合していることを意味します。

テストを (たとえば) 100000 アイテムに増やした場合、メッセージの生成と消費が混在していることがわかりますが、それでも長さが 10 以上のメッセージのブロックが表示される場合がproducingあります。consuming

もう 1 つの試みは、コンシューマを最初に起動し、Thread.sleep(10);起動後に a を配置して、プロデューサを待機させることです。その後、消費者は電話をかける時間があり、最初の呼び出しが行われるとすぐに からにwait()移動します。ただし、その場合でも、競合状態により、. これが、マルチスレッド アプリケーションの非同期の性質です。WAITBLOCKEDnotifyAll()producingconsuming

ps 適切に処理するのは常に良いパターンInterruptedExceptionです。次のようにする必要があります。

try {
    wait(); // give up lock and wait
} catch (InterruptedException e) {
    // reset the thread interrupt flag
    Thread.currentThread().interrupt();
    // probably stopping the thread is best
    return;
}
于 2013-08-29T22:04:36.117 に答える
2

通知(およびnotifyAll)ドキュメントから

目覚めたスレッドは、現在のスレッドがこのオブジェクトのロックを放棄するまで先に進むことができません。起動されたスレッドは、このオブジェクトで同期するために活発に競合している可能性のある他のスレッドと通常の方法で競合します。たとえば、目覚めたスレッドは、このオブジェクトをロックする次のスレッドになることに関して、信頼できる特権や不利な点を享受しません。

表示されているのは、これら 2 つのスレッドがどのようにスケジュールされているかということです。

于 2013-08-29T22:08:21.637 に答える