0

最近、BlockingQueue のエンキューの次の実装を見ました ( source )

public synchronized void enqueue(Object item)
throws InterruptedException  {
  while(this.queue.size() == this.limit) {
    wait();
  }
  if(this.queue.size() == 0) {
    notifyAll();
  }
  this.queue.add(item);
}

whileループが必要な理由と、ループwhileを置き換えることができる理由if (this.queue.size() == this.limit)

メソッドのエンキューが同期されているように見えるため、一度に 1 つのスレッドのみがメソッド本体で実行され、wait(). this.queue.size() == this.limitスレッドが通知されたら、再度状態を確認せずに先に進むことはできませんか?

4

2 に答える 2

5

のドキュメントObject.wait()で最もよく説明されています。

スレッドは、通知、中断、またはタイムアウトなしでウェイクアップすることもできます。これは、いわゆるスプリアス ウェイクアップです。これが実際に発生することはめったにありませんが、アプリケーションは、スレッドが起動される原因となったはずの条件をテストし、条件が満たされない場合は待機し続けることで、これを防ぐ必要があります。つまり、次のように、待機は常にループで発生する必要があります。

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait(timeout);
     ... // Perform action appropriate to condition
 }
于 2012-03-23T12:59:23.887 に答える
4

いいえ。キュー内のスペースが開くのを待っている複数のスレッドが存在する可能性があり、notifyAll() 呼び出しによってすべてのスレッドが起動されるため、しばらく時間が必要です。

wait() メソッドは実際に同期モニターを解放して、他のスレッドが進行できるようにします。そうでない場合、キューからものを削除しようとするスレッドも、 get() メソッドで同期ブロックに入るのを待ってスタックします (たとえば)。

待機中のスレッドの 1 つだけが、部分的に空のキューを認識します。

実際、それらのどれもそうではありませんでした。まったく関係のない理由で、スレッドが notifyAll で起動された可能性があります。

于 2012-03-23T12:47:15.717 に答える