2

notify()の代わりに使用できる複数のプロデューサー/複数のコンシューマーキューを持つことが可能かどうかを調べようとしていますnotifyAll()。たとえば、以下の実装 (ソース: here ) では、単純にnotifyAll()for を切り替えることはできませんnotify()。なぜ切り替えられないのかは完全には明らかではないので、この問題を理解するのを手伝ってくれる人へのティーザーとして残しておきます.

したがって、以下のコードは壊れています。

public class BlockingQueue {

  private Object lock = new Object();

  private List queue = new LinkedList();
  private int  limit = 10;

  public BlockingQueue(int limit){
    this.limit = limit;
  }


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


  public Object dequeue()
  throws InterruptedException{
   synchronized(lock) {
    while(this.queue.size() == 0){
      lock.wait();
    }
    if(this.queue.size() == this.limit){
      lock.notify();
    }

    return this.queue.remove(0);
  }
 }
}
4

3 に答える 3

10

次の手順は、デッドロックにつながります。例を簡潔にするためにlimit を 1に設定しましょう。

  • E1 はアイテムをキューに入れます。
  • E2 がエンキューを試行 - 待機ループをチェック - すでに満杯 - 待機
  • E3 がエンキューを試行 - 待機ループをチェック - すでに満杯 - 待機

  • D1 がデキューを試み、同期ブロックを実行中

  • D2 がデキューを試行 - (同期された) ブロックへのエントリでブロック - D1 が原因
  • D3 がデキューを試行 - (同期された) ブロックへのエントリでブロック - D1 が原因

  • D1 はエンキューを実行中 - アイテムを取得し、通知を呼び出し、メソッドを終了します

  • 通知はたまたま E2 をウェイクアップします (つまり、「待機中のスレッド」)。
  • しかし、D2 は E2 ができる前に同期ブロックに入る (E2 はロックを再取得する必要がある) ため、E2 はエンキュー同期ブロックへのエントリでブロックします。
  • D2 は待機ループをチェックし、キューにアイテムがないため、待機します
  • D3 は D2 の後でブロックに入りますが、E2 の前に、待機ループをチェックし、キューにアイテムがないため待機します。

  • E3、D2、D3が待っています!

  • 最後に、E2 はロックを取得し、アイテムをキューに入れ、通知を呼び出し、メソッドを終了します。

  • E2 の通知により E3 が起動します (任意のスレッドを起動できることに注意してください)

  • E3 は待機ループの状態をチェックします。キューには既に項目があるため、待機します。
  • NOTIFY を呼び出すスレッドがなくなり、3 つのスレッドが永久に中断されます。

解決策: notify を notifyAll に置き換えます

于 2012-12-08T08:47:19.990 に答える
0

設計がどうであれ、notify()現在ロック オブジェクトで待機しているランダム スレッドを起動し、notifyAll()そのようなすべてのスレッドを (ランダムな順序で) 起動することを知っておいてください。

待機中のスレッドが、指定した種類のウェイクアップを処理するようにコーディングされている限り、問題はありません。

一方が他方よりも優れているわけではありません。ある状況notify()では最良の選択ですが、別の状況では、notifyAll()取り組む問題によって異なります。

于 2012-12-08T05:51:56.873 に答える
0

両方notifyの方法で条件文を削除すると (条件は不要になりました)、すべてが正しく機能するはずです。

そして、元のソースではメソッドが同期されていました。なぜこれを に変更したのsynchronized(lock)ですか? に変更waitするのを忘れるだけlock.wait()ですか?

于 2012-12-08T06:21:39.737 に答える