Java Language Piège: utilisation incorrecte de wait () / notify ()


Exemple

Les méthodes object.wait() , object.notify() et object.notifyAll() sont destinées à être utilisées de manière très spécifique. (voir http://stackoverflow.com/documentation/java/5409/wait-notify#t=20160811161648303307 )

Le problème "Notification perdue"

Une erreur courante des débutants consiste à appeler inconditionnellement object.wait()

private final Object lock = new Object();

public void myConsumer() {
    synchronized (lock) {
        lock.wait();     // DON'T DO THIS!!
    }
    doSomething();
}

La raison en est que cela dépend d'un autre thread à appeler lock.notify() ou lock.notifyAll() , mais rien ne garantit que l'autre thread n'a pas effectué cet appel avant le thread consommateur appelé lock.wait() .

lock.notify() et lock.notifyAll() ne font rien du tout si un autre thread n'attend pas déjà la notification. Le thread qui appelle myConsumer() dans cet exemple sera bloqué pour toujours s'il est trop tard pour intercepter la notification.

Le bogue "État de surveillance illégal"

Si vous appelez wait() ou notify() sur un objet sans le verrouiller, la machine IllegalMonitorStateException .

public void myConsumer() {
    lock.wait();      // throws exception
    consume();
}

public void myProducer() {
    produce();
    lock.notify();    // throws exception
}

(La conception de wait() / notify() exige que le verrou soit maintenu car cela est nécessaire pour éviter les conditions de concurrence systémiques. S'il était possible d'appeler wait() ou notify() sans verrouiller, il serait impossible de l'implémenter le principal cas d'utilisation de ces primitives: attendre qu'une condition se produise.)

Attendre / notifier est trop bas

La meilleure façon d'éviter les problèmes avec wait() et notify() est de ne pas les utiliser. La plupart des problèmes de synchronisation peuvent être résolus en utilisant les objets de synchronisation de niveau supérieur (files d'attente, barrières, sémaphores, etc.) disponibles dans le package java.utils.concurrent .