171 votes

IllegalMonitorStateException sur l'appel wait()

J'utilise le multi-threading en java pour mon programme. J'ai exécuté le thread avec succès, mais lorsque j'utilise la fonction Thread.wait() c'est jeter java.lang.IllegalMonitorStateException . Comment faire pour qu'un fil attende d'être notifié ?

3 votes

Thread.wait() n'existe pas, il pourrait s'agir de this.wait()

187voto

reccles Points 2282

Vous devez être dans un synchronized afin que Object.wait() pour travailler.

De plus, je vous recommande de regarder les paquets de concurrence plutôt que les paquets de threading de la vieille école. Ils sont plus sûrs et bien plus facile à travailler .

EDIT

J'ai supposé que vous vouliez dire Object.wait() car votre exception est ce qui se passe lorsque vous essayez d'obtenir un accès sans détenir le verrou des objets.

1 votes

Bien vu. J'ai supposé qu'il voulait dire Object.wait() et qu'il était appelé depuis un thread.

2 votes

Un bloc synchronisé sur l'objet que vous attendez. Pourriez-vous modifier cette réponse pour la rendre un peu plus claire ? Merci.

57voto

wait est défini dans Object et non pas elle Thread . Le moniteur sur Thread est un peu imprévisible.

Bien que tous les objets Java disposent de moniteurs, il est généralement préférable de disposer d'un verrou dédié :

private final Object lock = new Object();

Vous pouvez obtenir des diagnostics légèrement plus faciles à lire, avec un faible coût en mémoire (environ 2K par processus) en utilisant une classe nommée :

private static final class Lock { }
private final Object lock = new Lock();

Afin de wait ou notify / notifyAll un objet, vous devez détenir le verrou avec l'objet synchronized déclaration. Vous aurez également besoin d'un while pour vérifier la condition de réveil (trouvez un bon texte sur le threading pour expliquer pourquoi).

synchronized (lock) {
    while (!isWakeupNeeded()) {
        lock.wait();
    }
}

A notifier :

synchronized (lock) {
    makeWakeupNeeded();
    lock.notifyAll();
}

Il vaut la peine d'apprendre à comprendre à la fois le langage Java et le système de gestion de l'information. java.util.concurrent.locks serrures (et java.util.concurrent.atomic ) lorsqu'on aborde le multithreading. Mais utilisez java.util.concurrent structures de données chaque fois que vous le pouvez.

5 votes

Je n'ai jamais compris comment cela fonctionne, étant donné que le wait et le notify sont tous deux dans des blocs synchronisés sur le même objet (lock). Puisque le thread wait est dans le bloc, le thread notify ne devrait-il pas bloquer sur la ligne "synchronized (lock)" ?

6 votes

@Brent212 Pour toute méthode autre que wait oui, tu n'arriveras jamais à notify . Cependant, dans les documents de l'API pour Object.wait "Le fil libère la propriété de ce moniteur". Ainsi, alors que dans wait c'est comme s'il était à l'extérieur de l'enceinte. synchronized blocs (pour le même objet, il peut y avoir plusieurs synchronized sur le même objet).

26voto

Mina Points 99

Je sais que ce fil de discussion date de presque 2 ans, mais je dois quand même le fermer car je suis également venu à cette session de questions/réponses avec le même problème...

Veuillez lire cette définition de illegalMonitorException encore et encore...

L'exception IllegalMonitorException est levée pour indiquer qu'un thread a tenté d'attendre sur le moniteur d'un objet ou pour notifier d'autres threads en attente sur le moniteur d'un objet sans posséder le moniteur spécifié.

Cette ligne dit encore et encore, IllegalMonitorException vient quand une des 2 situations se produit....

1> attendre sur le moniteur d'un objet sans posséder le moniteur spécifié.

2> notifier d'autres threads en attente sur le moniteur d'un objet sans posséder le moniteur spécifié.

Certains ont peut-être trouvé leurs réponses... mais ceux qui ne les ont pas trouvées sont priés de vérifier 2 déclarations.....

synchronisé (objet)

objet.wait()

Si les deux objet sont les mêmes... alors aucune illegalMonitorException ne peut venir.

Maintenant, relisez la définition de l'exception IllegalMonitorException et vous ne l'oublierez plus...

0 votes

En fait, ça ne marche pas. Je l'ai essayé. Je crée un Runnable, je le verrouille (en utilisant un bloc synchronisé) et à l'intérieur de ce bloc, je lance le Runnable sur le UI-thread (Android) et après cela, je fais myRunnable.wait(), et j'obtiens toujours l'exception.

0 votes

Excelente explication !! Je faisais wait() sans spécifier l'objet, donc il prenait l'instance, et se synchronisait sur un autre objet. Maintenant j'utilise otherObject.wait() et ça marche !

6voto

Stephen C Points 255558

D'après vos commentaires, il semble que vous fassiez quelque chose comme ça :

Thread thread = new Thread(new Runnable(){
    public void run() { // do stuff }});

thread.start();
...
thread.wait();

Il y a trois problèmes.

  1. Comme d'autres l'ont dit, obj.wait() ne peut être appelé que si le thread actuel détient le verrou primitif / mutex pour obj . Si le thread actuel ne détient pas le verrou, vous obtenez l'exception que vous voyez.

  2. En thread.wait() L'appel ne fait pas ce que vous semblez attendre de lui. Plus précisément, thread.wait() n'est pas faire attendre le fil nommé. Il provoque plutôt le fil actuel pour attendre qu'un autre thread appelle thread.notify() ou thread.notifyAll() .

    Il n'y a en fait aucun moyen sûr de forcer un Thread instance de faire une pause si elle ne le veut pas. (Ce qui se rapproche le plus de cela en Java est la fonction dépréciée Thread.suspend() mais cette méthode est intrinsèquement non sûre, comme l'explique la Javadoc).

    Si vous voulez que la nouvelle Thread pour faire une pause, la meilleure façon de le faire est de créer une CountdownLatch et que le thread appelle await() sur le loquet pour se mettre en pause. Le thread principal appelle alors countDown() sur le loquet pour laisser le fil en pause continuer.

  3. Orthogonal aux points précédents, en utilisant un Thread comme un verrou / mutex peut causer des problèmes. Par exemple, la javadoc pour Thread::join dit :

    Cette mise en œuvre utilise une boucle de this.wait appels conditionnés par this.isAlive . Lorsqu'un thread se termine, le this.notifyAll est invoquée. Il est recommandé aux applications de ne pas utiliser wait , notify ou notifyAll sur Thread instances.

0voto

Tadeusz Kopec Points 7625

L'appel Thread.wait() a un sens dans un code qui se synchronise sur l'objet Thread.class. Je ne pense pas que ce soit ce que vous vouliez dire.
Vous demandez

Comment faire en sorte qu'un fil de discussion attende d'être notifié ?

Vous pouvez faire attendre uniquement votre thread actuel. Tout autre thread ne peut être que gentiment invité à attendre, s'il est d'accord.
Si vous voulez attendre une certaine condition, vous avez besoin d'un objet verrouillé - l'objet Thread.class est un très mauvais choix - c'est un singleton AFAIK donc la synchronisation sur lui (sauf pour les méthodes statiques Thread) est dangereuse.
Les détails de la synchronisation et de l'attente sont déjà expliqués par Tom Hawtin. java.lang.IllegalMonitorStateException signifie que vous essayez d'attendre sur un objet sur lequel vous n'êtes pas synchronisé - il est illégal de le faire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X