2009-05-06 10 views
5

Que se passe-t-il lorsque vous appelez la méthode notifyAll sur un objet qui n'attend pas? Devrait-il y avoir une exception ou est-ce une situation normale?Java - wait et notifyAll

Répondre

6

C'est tout à fait normal. Vous pouvez seulement notifier tout ce qui attend sur un seul moniteur. Tout le monde n'est pas intéressé. L'objet sur lequel vous appelez notifyAll est uniquement le moniteur sur lequel les autres attendent. Si personne n'attend, personne ne doit être averti

8

Comme vous pouvez le voir ici, l'appel de notifyAll() sur un objet non en attente n'a aucun effet.

alt text

+0

Il pourrait ne pas être tout à fait correct de mettre un fil d'attente à l'exécution sur notifyAll ou du moins pas sans la mise en garde que la première chose qu'un fil est notifié ne regrab le verrou du moniteur. Et puisque seul un nombre de threads notifiés peut l'attraper, les autres seront bloqués. Mais le blocage n'est pas la même chose que l'attente car le thread bloqué n'a pas besoin d'un autre signal notify(). –

1

objets en attente seulement averti. Object.wait() bloque jusqu'à un délai d'attente ou de notification - la question reste donc de savoir comment ou pourquoi pensez-vous que les objets non-attendus seraient jamais notifiés? cela n'a aucun sens.

+0

Les objets n'attendent pas ou sont notifiés - les threads le font. Et il est parfaitement possible et normal d'appeler notifyAll() sur un objet moniteur sans savoir si des threads l'attendent ou non. Par exemple, dans un scénario producteur/consommateur avec une file d'attente, le consommateur peut avoir vidé la file d'attente et être occupé par le traitement lorsque le producteur ajoute un nouvel élément à la file d'attente et avertit tous les consommateurs qui attendent (c'est-à-dire –

+0

J'ai éliminé Thread pour que les choses restent aussi simples que possible. –

2

L'objet est "en attente", ne pas attendre lui-même. Le fil est celui qui attend. Si personne n'attend, personne ne se réveillera et rien de spécial ne se produira.

+0

Que se passe-t-il lorsqu'une alarme se déclenche mais qu'il n'y a personne pour l'entendre? –

2

Situation parfaitement normale. Imaginons que vous ayez une file d'attente avec un thread producteur qui y ajoute des éléments et un thread consommateur qui en supprime des éléments.

Maintenant que le consommateur a pu vider la file d'attente et être encore occupé par le traitement, personne n'attend que la file devienne non vide. Maintenant, le producteur ajoute un nouvel élément à la file d'attente. Il doit appeler notifyAll() pour réveiller le consommateur s'il attendait. Ajouter une logique supplémentaire pour vérifier si quelqu'un est en attente et n'appeler que notifyAll() dans ce cas ajouterait une complexité considérable (et très sujette à défaillance) au scénario - il est beaucoup plus facile d'appeler notifyAll() à chaque fois.

1

Je ne fais peut-être que fractionner les cheveux ;-) Il peut ne pas être strictement correct de penser à des threads qui passent de l'état 'waiting' à l'état 'running' sur notifyAll; au moins non sans la mise en garde que la première chose qu'un thread notifié fait est regrab le verrouillage du moniteur. Et puisque seul un des threads notifiés peut l'attraper, les autres seront bloqué. BLOQUÉ (Thread.State.Blocked) correspond à l'état du thread. Mais le blocage est pas la même chose que l'attente car le thread bloqué n'a pas besoin d'un autre signal notify() pour reprendre. [Eh bien, je connais des réveils intempestifs mais peut-être que le contraire pourrait également être vrai pour certaines implémentations JVM - un avis manqué?]

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

Peut-on manquer une notification? –