"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > Pourquoi un thread réacquiert-il toujours le verrouillage d'objet après notify() ou notifyAll() ?

Pourquoi un thread réacquiert-il toujours le verrouillage d'objet après notify() ou notifyAll() ?

Publié le 2024-11-16
Parcourir:868

Why Does One Thread Always Reacquire the Object Lock After notify() or notifyAll()?

La distinction subtile entre notify() et notifyAll()

Alors que la principale différence entre notify() et notifyAll() réside dans le nombre de threads en attente qu'ils réveillent (un contre tous), cela soulève une autre question :

Pourquoi un thread ré-acquiert-il toujours l'objet lock?

Dans le cas général, notify() et notifyAll() ne spécifient pas quel thread en attente sera sélectionné pour réacquérir le verrou. Le planificateur de threads JVM ou système effectue cette sélection, qui peut être non déterministe.

La nécessité de notifyAll()

Cependant, en utilisant notify() dans certains scénarios peut conduire à une impasse, comme l'illustre l'exemple suivant :

Classe Producteur/Consommateur avec notify()

public class ProducerConsumer {

    private final int MAX_SIZE = 1;  // Buffer size

    private List buf = new ArrayList();

    public synchronized void put(Object o) {
        while (buf.size() == MAX_SIZE) {
            wait();
        }
        buf.add(o);
        notify();
    }

    public synchronized Object get() {
        while (buf.size() == 0) {
            wait();
        }
        Object o = buf.remove(0);
        notify();
        return o;
    }
}

Scénario d'impasse :

  1. Le producteur P1 place un objet dans le tampon.
  2. Les producteurs P2 et P3 tentent de placer des objets mais sont bloqué car le tampon est plein.
  3. Le consommateur C1 tente d'obtenir un objet du tampon.
  4. C1 est en cours d'exécution et récupère l'objet, puis informe un thread en attente.
  5. P2 ou C2 peuvent être réveillés par la notification, mais ils sont tous deux bloqués en essayant de réacquérir le verrou.
  6. C3 est également bloqué en essayant d'acquérir le verrou.

En conséquence, les trois threads attendent indéfiniment, ce qui conduit à impasse.

La solution : notifyAll()

Pour résoudre cette impasse, il faut utiliser notifyAll() au lieu de notify() dans le code producteur/consommateur. Cela garantit que tous les threads en attente sont réveillés, évitant ainsi les blocages.

Recommandation :

Pour la plupart des scénarios, notifyAll() est la méthode préférée car elle évite les blocages potentiels. Si le scénario spécifique nécessite de réveiller un seul thread en attente spécifique, alors notify() peut être utilisé avec prudence.

Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3