J'utilise le multi-threading dans Java pour mon programme. J'ai exécuté le thread avec succès, mais lorsque j'utilise Thread.wait()
, il jette Java.lang.IllegalMonitorStateException
. Comment puis-je faire en sorte qu'un fil attende jusqu'à ce qu'il soit averti?
Vous devez être dans un bloc synchronized
pour que Object.wait()
fonctionne.
En outre, je vous recommande de regarder les packages de concurrence d'accès à la place des anciens packages de threading. Ils sont plus sûrs et plus faciles à utiliser .
Bonne codage.
EDIT
J'ai supposé que vous vouliez dire Object.wait()
car votre exception est ce qui se passe lorsque vous essayez d'accéder sans verrouiller les objets.
wait
est défini dans Object
et non pas Thread
. Le moniteur sur Thread
est un peu imprévisible.
Bien que tous les objets Java aient des moniteurs, il est généralement préférable d’avoir un verrou dédié:
private final Object lock = new Object();
Vous pouvez obtenir des diagnostics un peu plus faciles à lire, avec un faible coût en mémoire (environ 2 Ko 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 conserver le verrou avec l'instruction synchronized
. En outre, vous aurez besoin d'une boucle while
pour vérifier l'état de réveil (recherchez un bon texte sur le filetage pour expliquer pourquoi).
synchronized (lock) {
while (!isWakeupNeeded()) {
lock.wait();
}
}
Prévenir:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
Il est utile d’apprendre à comprendre à la fois le langage Java et les verrous Java.util.concurrent.locks
(et Java.util.concurrent.atomic
) lorsqu’on s’adonne au multithreading. Mais utilisez Java.util.concurrent
structures de données chaque fois que vous le pouvez.
Je sais que ce fil a presque 2 ans, mais j'ai encore besoin de le fermer car je suis également venu à cette session de questions/réponses avec le même problème ...
S'il vous plaît lire cette définition de illegMonitorException encore et encore ...
ne 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 encore et encore dit, IllegalMonitorException arrive quand une des 2 situations se produit ....
1> attendez sur le moniteur d'un objet sans posséder le moniteur spécifié.
2> notifiez les autres threads en attente sur le moniteur d'un objet sans posséder le moniteur spécifié.
Certains ont peut-être eu leurs réponses ... qui tous ne le font pas, alors s'il vous plaît vérifier 2 déclarations ....
synchronisé (objet)
object.wait ()
Si les deux objet sont identiques ... aucune exception illégaleMonitorException ne peut arriver.
Maintenant, lisez à nouveau la définition de IllegalMonitorException et vous ne l'oublierez plus ...
Sur la base de vos commentaires, vous semblez faire quelque chose comme ceci:
Thread thread = new Thread(new Runnable(){
public void run() { // do stuff }});
thread.start();
...
thread.wait();
Il y a trois problèmes.
Comme d'autres l'ont dit, obj.wait()
ne peut être appelé que si le thread en cours détient le verrou/mutex primitif pour obj
. Si le thread actuel ne tient pas le verrou, vous obtenez l'exception que vous voyez.
L'appel thread.wait()
ne fait pas ce que vous semblez attendre. Plus précisément, thread.wait()
ne le fait pas fait attendre le thread désigné. Cela provoque plutôt le thread actuel d'attendre qu'un autre thread appelle thread.notify()
ou thread.notifyAll()
.
Il n'existe en réalité aucun moyen sûr de forcer une instance Thread
à s'interrompre si elle ne le souhaite pas. (La méthode la plus proche de Java est la méthode obsolète Thread.suspend()
, mais cette méthode est intrinsèquement dangereuse, comme expliqué dans la Javadoc.)
Si vous voulez que le Thread
nouvellement démarré marque une pause, la meilleure façon de le faire est de créer une instance CountdownLatch
et de laisser l'appel de thread await()
sur le loquet se mettre en pause. Le thread principal appelle ensuite countDown()
sur le loquet pour laisser le thread en pause continuer.
Orthogonal aux points précédents, l’utilisation d’un objet Thread
comme verrou/mutex peut poser des problèmes. Par exemple, le javadoc pour Thread::join
dit:
Cette implémentation utilise une boucle d'appels
this.wait
subordonnée àthis.isAlive
. Lorsqu'un thread se termine, la méthodethis.notifyAll
est appelée. Il est recommandé aux applications de ne pas utiliser les instanceswait
,notify
ounotifyAll
surThread
.
Pour traiter l'exception IllegalMonitorStateException, vous devez vérifier que tous les appels des méthodes wait, notify et notifyAll ont lieu uniquement lorsque l'appelant le thread possède le moniteur approprié. La solution la plus simple consiste à inclure ces appels dans des blocs synchronisés. L'objet de synchronisation qui doit être appelé dans l'instruction synchronisée est celui dont le moniteur doit être acquis.
Voici l'exemple simple pour comprendre le concept de moniteur
public class SimpleMonitorState {
public static void main(String args[]) throws InterruptedException {
SimpleMonitorState t = new SimpleMonitorState();
SimpleRunnable m = new SimpleRunnable(t);
Thread t1 = new Thread(m);
t1.start();
t.call();
}
public void call() throws InterruptedException {
synchronized (this) {
wait();
System.out.println("Single by Threads ");
}
}
}
class SimpleRunnable implements Runnable {
SimpleMonitorState t;
SimpleRunnable(SimpleMonitorState t) {
this.t = t;
}
@Override
public void run() {
try {
// Sleep
Thread.sleep(10000);
synchronized (this.t) {
this.t.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Puisque vous n'avez pas posté de code, nous travaillons en quelque sorte dans le noir. Quels sont les détails de l'exception?
Est-ce que vous appelez Thread.wait () depuis le thread ou en dehors de celui-ci?
Je pose cette question car, selon le javadoc de IllegalMonitorStateException, il s’agit:
Lancé 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é.
Pour clarifier cette réponse, cet appel à attendre sur un thread lève également IllegalMonitorStateException, bien qu’il ait été appelé à partir d’un bloc synchronisé:
private static final class Lock { }
private final Object lock = new Lock();
@Test
public void testRun() {
ThreadWorker worker = new ThreadWorker();
System.out.println ("Starting worker");
worker.start();
System.out.println ("Worker started - telling it to wait");
try {
synchronized (lock) {
worker.wait();
}
} catch (InterruptedException e1) {
String msg = "InterruptedException: [" + e1.getLocalizedMessage() + "]";
System.out.println (msg);
e1.printStackTrace();
System.out.flush();
}
System.out.println ("Worker done waiting, we're now waiting for it by joining");
try {
worker.join();
} catch (InterruptedException ex) { }
}
J'ai reçu un IllegalMonitorStateException
en essayant de réveiller un fil dans/à partir d'un autre class
/fil. Dans Java 8
, vous pouvez utiliser les lock
fonctionnalités de la nouvelle API de simultanéité à la place de synchronized
fonctions.
Je stockais déjà des objets pour les transactions asynchronous
websocket dans un fichier WeakHashMap
. La solution dans mon cas était aussi de stocker un objet lock
dans un ConcurrentHashMap
pour synchronous
réponses. Remarque le condition.await
(pas .wait
).
Pour gérer le multi threading, j’utilisais une Executors.newCachedThreadPool()
pour créer un pool de threads .
L'appel de Thread.wait () est logique dans un code qui se synchronise sur l'objet Thread.class. Je ne pense pas que c'est ce que tu voulais dire.
Tu demandes
Comment puis-je faire en sorte qu'un fil attende jusqu'à ce qu'il soit averti?
Vous pouvez uniquement faire patienter votre thread actuel. Tout autre sujet ne peut être que doucement invité à attendre, s'il est d'accord.
Si vous voulez attendre une condition, vous avez besoin d’un objet verrou (l’objet Thread.class est un très mauvais choix). Il s’agit d’un singleton AFAIK. Par conséquent, sa synchronisation (à l’exception des méthodes statiques Thread) est dangereuse.
Tom Hawtin a déjà expliqué les détails de la synchronisation et de l'attente. Java.lang.IllegalMonitorStateException
signifie que vous essayez d'attendre un objet sur lequel vous n'êtes pas synchronisé - il est illégal de le faire.
Ceux qui utilisent Java 7.0 ou une version antérieure peuvent se référer au code que j'ai utilisé ici et cela fonctionne.
public class WaitTest {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void waitHere(long waitTime) {
System.out.println("wait started...");
lock.lock();
try {
condition.await(waitTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.unlock();
System.out.println("wait ends here...");
}
public static void main(String[] args) {
//Your Code
new WaitTest().waitHere(10);
//Your Code
}
}
Je ne sais pas si cela aidera quelqu'un d'autre ou non, mais c'était l'élément clé pour résoudre mon problème dans la réponse de l'utilisateur "Tom Hawtin - tacklin" ci-dessus:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
Juste le fait que le "verrou" soit passé comme argument dans synchronized () et qu'il soit également utilisé dans "verrouiller" .notifyAll ();
Une fois que je l'ai fait dans ces 2 endroits je l'ai fait travailler