2009-05-06 14 views
5

待機していないオブジェクトでnotifyAllメソッドを呼び出すとどうなりますか?例外があるか、それとも通常の状況ですか?Java待機とnotifyAll

答えて

6

これは完全に正常です。 1つのモニターで待機しているすべてのものに通知することができます。誰もが興味がありません。 notifyAllを呼び出すオブジェクトは、ほかの人が待機しているモニタだけです。誰も待機していない場合、誰にも通知する必要はありません。

8

ここでわかるように、待機していないオブジェクトでnotifyAll()を呼び出すことは効果がありません。

alt text

+0

通知スレッドが最初に行うことは、モニターロックregrabであることを警告なしでのnotifyAll上で動作しているか、少なくともしないように待機してからスレッドを置くことが厳密には正しくない可能性があります。通知されたスレッド数のうちの1つのみがそれを取得できるため、他のスレッドはブロックされます。しかし、ブロックされたスレッドは別のnotify()シグナルを必要としないため、ブロックは待機と同じではありません。 –

1

だけ待っているオブジェクトは、通知を得ます。 Object.wait()はタイムアウトまたは通知するまでブロックします。したがって、待機していないオブジェクトが通知される方法や理由は何ですか?意味がない。

+0

オブジェクトは待機しないか、スレッドに通知されます。また、モニタオブジェクト上でnotifyAll()を呼び出すには、スレッドが待機中であるかどうかを知らずに完全に可能であり正常です。たとえば、キュ​​ーを持つプロデューサ/コンシューマシナリオでは、コンシューマはキューを空にした後、プロデューサがキューに新しい要素を追加し、待機しているすべてのコンシューマ(つまりnone)に通知します。 –

+0

スレッドを削除してできるだけシンプルにしました。 –

2

オブジェクトは待機しておらず、待機していません。スレッドは待っているスレッドです。誰も待っていない場合、誰も目を覚ますことはなく、特別なことは起こりません。

+0

アラームが鳴っても何も聞こえないときはどうなりますか? –

2

完全に正常な状況です。

プロデューサスレッドに要素を入れてキューを作成し、要素から要素を削除するコンシューマスレッドがあるとします。

これで、コンシューマはキューを空にしてもまだ処理されている可能性があるので、誰もキューが空でなくなるのを待っていません。プロデューサはキューに新しい要素を追加します。待機していた場合、消費者を起こすためにnotifyAll()を呼び出さなければなりません。誰かが待っているかどうかをチェックする追加のロジックを追加し、その場合notifyAll()を呼び出すだけで、シナリオに相当な(そして非常に失敗しやすい)複雑さが追加されます。毎回notifyAll()を呼び出すほうがはるかに簡単です。

1

私は分かれているかもしれません;-)スレッドはnotifyAllで 'waiting'状態から 'running'状態に置かれていると考えるのは厳密に正しいとは限りません。通知されたスレッドが最初に行うことは、少なくともモニタロックを再確認することです。そして、通知されたスレッドの数のうちの1つのみがそれをつかむことができるので、他はをブロックし、になります。 ブロックthread.state.blacked)はスレッド状態です。ブロッキングはで、ブロックされたスレッドは別のnotify()シグナルを再開する必要がないため、と同じではありません。 [私は偽の起き上がりを知っていますが、逆の場合もあるJVMの実装では真実かもしれません。]

public class HellBoy { 
    public static class MyThread extends Thread { 
     static final public Object sharedLock = new Object(); 

     public void run() { 
      synchronized (sharedLock) { 
       System.out.println("Gonna wait..."); 
       try { 
        sharedLock.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
       System.out.println("Woken up but sleeping with the lock"); 
       try { 
        Thread.sleep(2500); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
       System.out.println("exiting and unlocking"); 
      } 
     } 
    } 

    public static void main(String[] args) throws Exception { 
     new MyThread().start(); 
     new MyThread().start(); 
     new MyThread().start(); 
     new MyThread().start(); 
     Thread.sleep(200); 
     synchronized (MyThread.sharedLock) { 
      MyThread.sharedLock.notifyAll(); 
     } 
    } 
} 
+0

通知を紛失することはできますか? –