Question

Pourquoi ce programme de test génère-t-il une java.lang.IllegalMonitorStateException ?

public class test {
    static Integer foo = new Integer(1);
    public static void main(String[] args) {
        synchronized(foo) {
            foo++;
            foo.notifyAll();
        }
        System.err.println("Success");
    }
}

Résultat:

Exception in thread "main" java.lang.IllegalMonitorStateException
        at java.lang.Object.notifyAll(Native Method)
        at test.main(test.java:6)
Était-ce utile?

La solution

Vous avez bien noté que notifyAll doit être appelé à partir d'un bloc synchronisé.

Cependant, dans votre cas, en raison de la boxe automatique, l'objet sur lequel vous avez synchronisé n'est pas la même instance que celle sur laquelle vous avez invoqué notifyAll . En fait, la nouvelle instance foo incrémentée est toujours confinée à la pile et aucun autre thread ne peut éventuellement être bloqué lors d'un appel wait .

Vous pouvez implémenter votre propre compteur modifiable sur lequel la synchronisation est effectuée. En fonction de votre application, vous pouvez également trouver AtomicInteger répond à vos besoins.

Autres conseils

Vous devriez également vous méfier de verrouiller ou de notifier des objets tels que String et Integer qui peuvent être internés par la machine virtuelle Java (pour empêcher la création de nombreux objets qui représentent l'entier 1 ou la chaîne "").

L’incrémentation de l’entier fait disparaître l’ancien foo et le remplace par un nouvel objet foo qui n’est pas synchronisé avec la variable foo précédente.

Voici une implémentation d'AtomicInteger proposée par erickson ci-dessus. Dans cet exemple, foo.notifyAll (); ne produit pas de java.lang.IllegalMonitorStateException car l'objet AtomicInteger n'est pas actualisé lorsque foo.incrementAndGet (); est exécuté.

import java.util.concurrent.atomic.AtomicInteger;

public class SynchronizeOnAPrimitive {
    static AtomicInteger foo = new AtomicInteger(1);
    public static void main(String[] args) {
        synchronized (foo) {
            foo.incrementAndGet();
            foo.notifyAll();
        }
        System.out.println("foo is: " + foo);
    }
}

Sortie:

foo is: 2

Comme l'a noté erickson, le code sans l'opérateur postincrément fonctionne sans erreur:

static Integer foo = new Integer(1);

public static void main(String[] args) {
    synchronized (foo) {
        foo.notifyAll();
    }
    System.out.println("Success");
}

sortie:

  

Succès

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top