Sto usando il multi-threading in Java per il mio programma. Ho eseguito correttamente il thread, ma quando lo sto usando Thread.wait()
, sta lanciando java.lang.IllegalMonitorStateException
. Come posso attendere che un thread venga avvisato?
Sto usando il multi-threading in Java per il mio programma. Ho eseguito correttamente il thread, ma quando lo sto usando Thread.wait()
, sta lanciando java.lang.IllegalMonitorStateException
. Come posso attendere che un thread venga avvisato?
Risposte:
Devi essere in un synchronized
blocco per Object.wait()
funzionare.
Inoltre, raccomando di esaminare i pacchetti di concorrenza anziché i pacchetti di threading della vecchia scuola. Sono più sicuri e molto più facili da lavorare .
Buona codifica.
MODIFICARE
Supponevo che intendessi Object.wait()
come eccezione, ciò che accade quando provi ad accedere senza tenere il blocco degli oggetti.
wait
è definito in Object
, e non in esso Thread
. Il monitor acceso Thread
è un po 'imprevedibile.
Sebbene tutti gli oggetti Java abbiano monitor, in genere è meglio avere un blocco dedicato:
private final Object lock = new Object();
Puoi leggere un po 'più facilmente la diagnostica, con un piccolo costo di memoria (circa 2K per processo) usando una classe denominata:
private static final class Lock { }
private final Object lock = new Lock();
Per wait
o notify
/ notifyAll
un oggetto, devi tenere il lucchetto con l' synchronized
istruzione. Inoltre, avrai bisogno di un while
ciclo per verificare la condizione di sveglia (trova un buon testo sul threading per spiegare il perché).
synchronized (lock) {
while (!isWakeupNeeded()) {
lock.wait();
}
}
Notificare:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
Vale la pena comprendere sia il linguaggio Java che i java.util.concurrent.locks
blocchi (e java.util.concurrent.atomic
) quando si accede al multithreading. Ma usa java.util.concurrent
le strutture dati ogni volta che puoi.
wait
, sì, non ci riusciresti mai notify
. Tuttavia, nei documenti API per Object.wait
"Il thread rilascia la proprietà di questo monitor". Quindi, mentre wait
è come se fosse al di fuori dei synchronized
blocchi racchiusi (per lo stesso oggetto, possono esserci più synchronized
blocchi sullo stesso oggetto).
So che questo thread ha quasi 2 anni ma devo ancora chiuderlo poiché sono arrivato anche a questa sessione di domande e risposte con lo stesso problema ...
Leggere più volte questa definizione di illegalMonitorException ...
IllegalMonitorException viene generato per indicare che un thread ha tentato di attendere sul monitor di un oggetto o di avvisare altri thread in attesa sul monitor di un oggetto senza possedere il monitor specificato.
Questa riga dice ancora e ancora, IllegalMonitorException arriva quando si verifica una delle 2 situazioni ....
1> attendere sul monitor di un oggetto senza possedere il monitor specificato.
2> notifica ad altri thread in attesa sul monitor di un oggetto senza possedere il monitor specificato.
Alcuni potrebbero avere le loro risposte ... chi non lo fa, quindi controlla 2 dichiarazioni ...
sincronizzato (oggetto)
object.wait ()
Se entrambi gli oggetti sono uguali ... non può arrivare nessuna illegalitàMonitorException.
Ora leggi di nuovo la definizione di IllegalMonitorException e non la dimenticherai più ...
Sulla base dei tuoi commenti sembra che tu stia facendo qualcosa del genere:
Thread thread = new Thread(new Runnable(){
public void run() { // do stuff }});
thread.start();
...
thread.wait();
Ci sono tre problemi.
Come altri hanno già detto, obj.wait()
può essere chiamato solo se il thread corrente contiene il blocco / mutex primitivo per obj
. Se il thread corrente non contiene il blocco, ottieni l'eccezione che stai vedendo.
La thread.wait()
chiamata non fa ciò che sembra aspettarsi che faccia. In particolare, thread.wait()
non fa attendere il thread nominato. Piuttosto, fa sì che il thread corrente attenda fino a quando qualche altro thread chiama thread.notify()
o thread.notifyAll()
.
In realtà non esiste un modo sicuro per forzare Thread
un'istanza a mettere in pausa se non lo desidera. (Il più vicino che Java ha a questo è il Thread.suspend()
metodo deprecato , ma quel metodo è intrinsecamente pericoloso, come spiegato in Javadoc.)
Se si desidera Thread
mettere in pausa il nuovo avvio , il modo migliore per farlo è creare CountdownLatch
un'istanza e fare in modo che la chiamata di thread await()
sul latch si metta in pausa. Il thread principale chiamerebbe quindi countDown()
il latch per consentire al thread sospeso di continuare.
Ortogonale ai punti precedenti, l'utilizzo di un Thread
oggetto come blocco / mutex può causare problemi. Ad esempio, il javadoc per Thread::join
dice:
Questa implementazione utilizza un ciclo di
this.wait
chiamate condizionatethis.isAlive
. Quando un thread terminathis.notifyAll
, viene invocato il metodo. Si raccomanda di non utilizzare le applicazioniwait
,notify
onotifyAll
suThread
istanze.
Dal momento che non hai pubblicato il codice, stiamo lavorando al buio. Quali sono i dettagli dell'eccezione?
Stai chiamando Thread.wait () dall'interno del thread o all'esterno di esso?
Lo chiedo perché secondo javadoc per IllegalMonitorStateException, è:
Generato per indicare che un thread ha tentato di attendere sul monitor di un oggetto o di avvisare altri thread in attesa sul monitor di un oggetto senza possedere il monitor specificato.
Per chiarire questa risposta, questa chiamata ad attendere su un thread genera anche IllegalMonitorStateException, nonostante venga chiamata da un blocco sincronizzato:
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) { }
}
wait()
.
worker.wait()
linea? Quindi dovresti sincronizzare il lavoratore, non il blocco.
Per gestire IllegalMonitorStateException, è necessario verificare che tutte le chiamate di attesa, notifica e notifica Tutti i metodi avvengano solo quando il thread chiamante possiede il monitor appropriato . La soluzione più semplice è racchiudere queste chiamate all'interno di blocchi sincronizzati. L'oggetto di sincronizzazione che deve essere invocato nell'istruzione sincronizzata è quello il cui monitor deve essere acquisito.
Ecco il semplice esempio per comprendere il concetto di monitor
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();
}
}
}
La chiamata Thread.wait () ha senso all'interno di un codice che si sincronizza sull'oggetto Thread.class. Non penso sia quello che volevi dire.
Tu chiedi
Come posso attendere che un thread venga avvisato?
Puoi far aspettare solo il tuo thread attuale. Qualsiasi altro thread può essere gentilmente invitato ad attendere, se concordato.
Se vuoi aspettare qualche condizione, hai bisogno di un oggetto lock - L'oggetto Thread.class è una scelta pessima - è un AFAIK singleton, quindi la sincronizzazione su di esso (ad eccezione dei metodi statici Thread) è pericolosa.
I dettagli per la sincronizzazione e l'attesa sono già stati spiegati da Tom Hawtin.
java.lang.IllegalMonitorStateException
significa che stai provando ad aspettare un oggetto su cui non sei sincronizzato - è illegale farlo.
Non sono sicuro che questo possa aiutare qualcun altro o no, ma questa è stata la parte fondamentale per risolvere il mio problema nella risposta sopra "Tom Hawtin - tacklin" dell'utente:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
Solo il fatto che il "lock" sia passato come argomento in synchronized () e sia anche usato in "lock" .notifyAll ();
Una volta che l'ho fatto in quei 2 posti l'ho fatto funzionare
Ho ricevuto un IllegalMonitorStateException
po 'di tempo cercando di svegliare un thread in / da un altro class
/ thread. In java 8
è possibile utilizzare le lock
caratteristiche del nuovo Concurrency API invece di synchronized
funzioni.
Stavo già memorizzando oggetti per asynchronous
transazioni di websocket in a WeakHashMap
. La soluzione nel mio caso era anche quella di memorizzare un lock
oggetto in aConcurrentHashMap
per le synchronous
risposte. Nota il condition.await
(non .wait
).
Per gestire il multi threading ho usato a Executors.newCachedThreadPool()
per creare un pool di thread .
Coloro che utilizzano Java 7.0 o versione precedente possono fare riferimento al codice che ho usato qui e funziona.
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
}
}