IllegalMonitorStateException in Java

1. Overzicht

In deze korte tutorial zullen we meer leren over java.lang.IllegalMonitorStateException.

We zullen een eenvoudige zender-ontvanger-applicatie maken die deze uitzondering genereert. Vervolgens bespreken we mogelijke manieren om dit te voorkomen. Ten slotte laten we zien hoe u deze afzender- en ontvangerklassen correct implementeert.

2. Wanneer wordt het geworpen?

De IllegalMonitorStateException is gerelateerd aan multithreading-programmering in Java. Als we een monitor waarop we willen synchroniseren, wordt deze uitzondering gegenereerd om aan te geven dat een thread heeft geprobeerd te wachten of om andere threads die op die monitor wachten op de hoogte te stellen, zonder dat deze de eigenaar is. In eenvoudigere woorden, we krijgen deze uitzondering als we een van de wacht(), melden (), of informerenAll () methoden van de Voorwerp klasse buiten een gesynchroniseerd blok.

Laten we nu een voorbeeld bouwen dat een IllegalMonitorStateException. Hiervoor gebruiken we beide wacht() en informerenAll () methoden om de gegevensuitwisseling tussen een zender en een ontvanger te synchroniseren.

Laten we eerst eens kijken naar het Gegevens klasse met het bericht dat we gaan verzenden:

openbare klasse Data {privé String-bericht; public void send (String bericht) {this.message = bericht; } public String ontvangen () {retourbericht; }}

Ten tweede, laten we de afzenderklasse maken die een IllegalMonitorStateException wanneer aangeroepen. Voor dit doel noemen we de informerenAll () methode zonder het in een gesynchroniseerd blok:

klasse UnsynchronizedSender implementeert Runnable {privé statisch definitief Logger-logboek = LoggerFactory.getLogger (UnsychronizedSender.class); privé definitieve gegevensgegevens; openbare UnsynchronizedSender (Data data) {this.data = data; } @Override public void run () {probeer {Thread.sleep (1000); data.send ("test"); data.notifyAll (); } catch (InterruptedException e) {log.error ("thread is onderbroken", e); Thread.currentThread (). Interrupt (); }}}

De ontvanger gaat ook een IllegalMonitorStateException. Net als in het vorige voorbeeld, bellen we naar de wacht() methode buiten een gesynchroniseerd blok:

openbare klasse UnsynchronizedReceiver implementeert Runnable {privé statisch definitief Logger-logboek = LoggerFactory.getLogger (UnsynchronizedReceiver.class); privé definitieve gegevensgegevens; privé String-bericht; openbare UnsynchronizedReceiver (Data data) {this.data = data; } @Override public void run () {probeer {data.wait (); this.message = data.receive (); } catch (InterruptedException e) {log.error ("thread is onderbroken", e); Thread.currentThread (). Interrupt (); }} public String getMessage () {retourbericht; }}

Laten we tot slot beide klassen instantiëren en een bericht tussen hen verzenden:

public void sendData () {Data data = nieuwe data (); UnsynchronizedReceiver-ontvanger = nieuwe UnsynchronizedReceiver (gegevens); Thread receiverThread = nieuwe Thread (receiver, "receiver-thread"); receiverThread.start (); UnsynchronizedSender afzender = nieuwe UnsynchronizedSender (data); Thread senderThread = nieuwe Thread (afzender, "sender-thread"); senderThread.start (); senderThread.join (1000); receiverThread.join (1000); }

Wanneer we dit stukje code proberen uit te voeren, ontvangen we een IllegalMonitorStateException van beiden Niet-gesynchroniseerde ontvanger en Niet-gesynchroniseerde afzender klassen:

[afzender-thread] FOUT com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedSender - Ongeldige uitzondering op de monitorstatus opgetreden java.lang.IllegalMonitorStateException: null op java.base / java.lang.Object.notifyAll (Native Method) op com.baeldung.exceptions .illegalmonitorstate.UnsynchronizedSender.run (UnsynchronizedSender.java:15) op java.base / java.lang.Thread.run (Thread.java:844) [ontvanger-thread] FOUT com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedReceiver - illegale monitor state-uitzondering opgetreden java.lang.IllegalMonitorStateException: null op java.base / java.lang.Object.wait (Native Method) op java.base / java.lang.Object.wait (Object.java:328) op com.baeldung. exception.illegalmonitorstate.UnsynchronizedReceiver.run (UnsynchronizedReceiver.java:12) op java.base / java.lang.Thread.run (Thread.java:844) 

3. Hoe dit te verhelpen

Om van de IllegalMonitorStateException, we moeten elke keer bellen wacht(), melden (), en informerenAll () methoden binnen een gesynchroniseerd blok. Laten we met dit in gedachten eens kijken hoe de juiste implementatie van het Afzender klasse zou er als volgt uit moeten zien:

klasse SynchronizedSender implementeert Runnable {private final Data data; openbare SynchronizedSender (Data data) {this.data = data; } @Override public void run () {gesynchroniseerd (data) {data.send ("test"); data.notifyAll (); }}}

Merk op dat we de gesynchroniseerd blok op hetzelfde Gegevens instantie noemen we later zijn informerenAll () methode.

Laten we de Ontvanger op dezelfde manier:

klasse SynchronizedReceiver implementeert Runnable {privé statisch definitief Logger-logboek = LoggerFactory.getLogger (SynchronizedReceiver.class); privé definitieve gegevensgegevens; privé String-bericht; openbare SynchronizedReceiver (Data data) {this.data = data; } @Override public void run () {gesynchroniseerd (data) {probeer {data.wait (); this.message = data.receive (); } catch (InterruptedException e) {log.error ("thread is onderbroken", e); Thread.currentThread (). Interrupt (); }}} public String getMessage () {retourbericht; }}

Als we beide klassen opnieuw maken en proberen hetzelfde bericht tussen beide te verzenden, werkt alles goed en wordt er geen uitzondering gegenereerd.

4. Conclusie

In dit artikel hebben we geleerd wat de oorzaken zijn IllegalMonitorStateException en hoe u dit kunt voorkomen.

Zoals altijd is de code beschikbaar op GitHub.