Mécanisme condition vs wait notify

Quel est l’avantage d’utiliser l’interface / les implémentations Condition par rapport au mécanisme de notification d’attente classique? Ici, je cite les commentaires écrits par Doug Lea:

Condition décompose les méthodes de contrôle Object (wait, notify et notifyAll) en objects distincts pour avoir plusieurs ensembles d’attente par object, en les combinant avec l’utilisation d’implémentations de locking arbitraires. Lorsqu’un verrou remplace l’utilisation de méthodes et d’instructions synchronisées, une condition remplace l’utilisation des méthodes de contrôle d’object.

Je vois que ceci est un moyen plus orienté object d’implémenter le mécanisme d’attente / notification. Mais y a-t-il un avantage sur le premier?

Il y a beaucoup d’ avantages comme mentionné ci-dessus à propos de l’ interface de condition, certains importants sont les suivants:

L’interface de condition est livrée avec deux méthodes supplémentaires:

1) booléen waitUntil (date limite) émet InterruptedException: provoque l’attente du thread en cours jusqu’à ce qu’il soit signalé ou interrompu ou que le délai spécifié soit écoulé.

2) waitingUninterruptibly (): le thread en cours attend qu’il soit signalé.

Si le statut d’interruption du thread en cours est défini lors de son entrée dans cette méthode ou s’il est interrompu en attente, il continuera d’attendre jusqu’à ce qu’il soit signalé. Lorsqu’il revient enfin de cette méthode, son état d’interruption sera toujours défini.

Les deux méthodes ci-dessus ne sont pas présentes dans le moniteur par défaut qui se trouve dans la classe d’object. Dans certaines situations, nous souhaitons définir la date limite pour que le thread attende, nous pouvons le faire par l’interface Condition.

Dans certaines situations, nous ne voulons pas que le thread soit interrompu et que vous souhaitiez que le thread en cours attende qu’il soit signalé, alors nous pouvons aller en attente. Une méthode ininterrompue présente dans l’interface de condition.

Pour plus d’informations Interface de documentation Documentation Java:

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html#awaitUntil%28java.util.Date%29

Le plus gros problème est que wait / notify est source d’erreurs pour les nouveaux développeurs. Le problème principal est de ne pas savoir comment les manipuler correctement si l’on obtient un bogue obscur.

  • si vous appelez notify () avant wait (), il est perdu.
  • il peut parfois être difficile de savoir si notify () et wait () sont appelés sur le même object.
  • Il n’y a rien en attente / notification qui nécessite un changement d’état, mais cela est nécessaire dans la plupart des cas.
  • wait () peut retourner de manière frauduleuse

La condition enveloppe cette fonctionnalité dans un composant dédié, mais elle se comporte de la même manière.

Il y a une question concernant wait / nofity publié minutes avant celle-ci et beaucoup, beaucoup plus Recherche [java] + wait + notify

Lorsque vous utilisez Condition: await()/signal() vous pouvez distinguer quel object ou groupe d’objects / threads reçoit un signal spécifique. Voici un court exemple où certains threads, les producteurs, recevront le signal isEmpty tandis que les consommateurs recevront le signal isFull :

 private volatile boolean usedData = true;//mutex for data private final Lock lock = new ReentrantLock(); private final Condition isEmpty = lock.newCondition(); private final Condition isFull = lock.newCondition(); public void setData(int data) throws InterruptedException { lock.lock(); try { while(!usedData) {//wait for data to be used isEmpty.await(); } this.data = data; isFull.signal();//broadcast that the data is now full. usedData = false;//tell others I created new data. }finally { lock.unlock();//interrupt or not, release lock } } public void getData() throws InterruptedException{ lock.lock(); try { while(usedData) {//usedData is lingo for empty isFull.await(); } isEmpty.signal();//tell the producers to produce some more. usedData = true;//tell others I have used the data. }finally {//interrupted or not, always release lock lock.unlock(); } } 

@AfterWorkGuinness

Ne devriez-vous pas définir usedData = true / false avant de signaler

Après le code de signal, allez jusqu’à la fin du bloc de locking et relâchez-le, donc l’ordre n’a pas d’importance

Pour répondre spécifiquement à la question de savoir pourquoi avoir plusieurs attentes est un avantage:

Avec wait / notify s’il y a différentes choses que les threads attendent (l’exemple le plus courant est une queue bloquante de taille fixe, certains threads mettant des choses dans la queue et bloquant lorsque la queue est pleine) lorsque la queue est vide), si vous utilisez notify, ce qui amène le planificateur à sélectionner un thread dans l’ensemble d’attente à notifier, vous pouvez avoir des cas où le thread choisi ne souhaite pas recevoir de notification pour une situation particulière. Par exemple, la queue notifiera pour append quelque chose à la queue, mais si le thread choisi est un producteur et que la queue est pleine, il ne peut pas agir sur cette notification, que vous auriez préféré à un consommateur. Avec le locking insortingnsèque, vous devez utiliser notifyAll pour vous assurer que les notifications ne sont pas perdues.

Mais notifyAll subit un désabonnement à chaque appel, où chaque thread se réveille et se dispute pour le verrou, mais un seul peut progresser. Les autres fils se heurtent tous à une dispute pour la serrure jusqu’à ce qu’ils puissent, un par un, acquérir le verrou et retourner très probablement à l’attente. Cela génère beaucoup de conflits pour peu d’avantages, il serait préférable de pouvoir utiliser notifier et de savoir qu’un seul thread est notifié, où la notification est pertinente pour ce thread.

C’est là qu’avoir des conditions distinctes à attendre est une grande amélioration. La queue peut invoquer un signal sur une condition et savoir qu’elle ne réveillera qu’un seul thread, où ce thread attend spécifiquement la condition.

La doc de l’API pour Condition contient un exemple de code qui montre l’utilisation de plusieurs conditions pour un tampon borné:

Nous aimerions continuer à mettre des threads en attente et à prendre des threads dans des ensembles d’attentes séparés afin que nous puissions utiliser l’optimisation consistant à ne notifier qu’un seul thread à la fois lorsque des éléments ou des espaces deviennent disponibles dans le tampon.