IllegalMonitorStateException in Java

1. Übersicht

In diesem kurzen Tutorial erfahren Sie mehr über java.lang.IllegalMonitorStateException.

Wir erstellen eine einfache Sender-Empfänger-Anwendung, die diese Ausnahme auslöst. Dann werden wir mögliche Wege diskutieren, um dies zu verhindern. Abschließend zeigen wir, wie diese Sender- und Empfängerklassen korrekt implementiert werden.

2. Wann wird es geworfen?

Die IllegalMonitorStateException bezieht sich auf die Multithreading-Programmierung in Java. Wenn wir einen Monitor haben, auf dem wir synchronisieren möchten, wird diese Ausnahme ausgelöst, um anzuzeigen, dass ein Thread versucht hat zu warten oder andere auf diesem Monitor wartende Threads zu benachrichtigen, ohne ihn zu besitzen. In einfacheren Worten, werden wir diese Ausnahme, wenn wir eine der Anruf wait () , notify (), oder notifyAll () Methoden der Objektklasse außerhalb eines synchronisierten Blocks.

Lassen Sie uns nun ein Beispiel erstellen , das eine IllegalMonitorStateException auslöst . Dazu verwenden wir die Methoden wait () und notifyAll () , um den Datenaustausch zwischen einem Sender und einem Empfänger zu synchronisieren.

Zunächst schauen sie sich an der Datenklasse, die die Nachricht hält wir senden gehen:

public class Data { private String message; public void send(String message) { this.message = message; } public String receive() { return message; } }

Zweitens erstellen wir die Absenderklasse, die beim Aufrufen eine IllegalMonitorStateException auslöst . Zu diesem Zweck rufen wir die notifyAll () -Methode auf, ohne sie in einen synchronisierten Block zu verpacken :

class UnsynchronizedSender implements Runnable { private static final Logger log = LoggerFactory.getLogger(UnsychronizedSender.class); private final Data data; public UnsynchronizedSender(Data data) { this.data = data; } @Override public void run() { try { Thread.sleep(1000); data.send("test"); data.notifyAll(); } catch (InterruptedException e) { log.error("thread was interrupted", e); Thread.currentThread().interrupt(); } } }

Der Empfänger wird auch eine IllegalMonitorStateException auslösen. Ähnlich wie im vorherigen Beispiel rufen wir die wait () -Methode außerhalb eines synchronisierten Blocks auf:

public class UnsynchronizedReceiver implements Runnable { private static final Logger log = LoggerFactory.getLogger(UnsynchronizedReceiver.class); private final Data data; private String message; public UnsynchronizedReceiver(Data data) { this.data = data; } @Override public void run() { try { data.wait(); this.message = data.receive(); } catch (InterruptedException e) { log.error("thread was interrupted", e); Thread.currentThread().interrupt(); } } public String getMessage() { return message; } }

Lassen Sie uns abschließend beide Klassen instanziieren und eine Nachricht zwischen ihnen senden:

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

Wenn wir versuchen, diesen Code auszuführen, erhalten wir eine IllegalMonitorStateException von den Klassen UnsynchronizedReceiver und UnsynchronizedSender :

[sender-thread] ERROR com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedSender - illegal monitor state exception occurred java.lang.IllegalMonitorStateException: null at java.base/java.lang.Object.notifyAll(Native Method) at com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedSender.run(UnsynchronizedSender.java:15) at java.base/java.lang.Thread.run(Thread.java:844) [receiver-thread] ERROR com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedReceiver - illegal monitor state exception occurred java.lang.IllegalMonitorStateException: null at java.base/java.lang.Object.wait(Native Method) at java.base/java.lang.Object.wait(Object.java:328) at com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedReceiver.run(UnsynchronizedReceiver.java:12) at java.base/java.lang.Thread.run(Thread.java:844) 

3. Wie man es repariert

Um loszuwerden der IllegalMonitorStateException, müssen wir jeden Anruf tätigen wait () , notify (), und notifyAll () Methoden in einem synchronisierten Block. Lassen Sie uns vor diesem Hintergrund sehen, wie die korrekte Implementierung der Sender- Klasse aussehen sollte:

class SynchronizedSender implements Runnable { private final Data data; public SynchronizedSender(Data data) { this.data = data; } @Override public void run() { synchronized (data) { data.send("test"); data.notifyAll(); } } }

Hinweis wir mit dem synchronisierten Block auf der gleichen Daten Instanz später wir seine Forderung notifyAll () Methode.

Lassen Sie uns den Empfänger auf die gleiche Weise reparieren :

class SynchronizedReceiver implements Runnable { private static final Logger log = LoggerFactory.getLogger(SynchronizedReceiver.class); private final Data data; private String message; public SynchronizedReceiver(Data data) { this.data = data; } @Override public void run() { synchronized (data) { try { data.wait(); this.message = data.receive(); } catch (InterruptedException e) { log.error("thread was interrupted", e); Thread.currentThread().interrupt(); } } } public String getMessage() { return message; } }

Wenn wir beide Klassen erneut erstellen und versuchen, dieselbe Nachricht zwischen ihnen zu senden, funktioniert alles einwandfrei und es wird keine Ausnahme ausgelöst.

4. Fazit

In diesem Artikel haben wir erfahren, was IllegalMonitorStateException verursacht und wie dies verhindert werden kann.

Wie immer ist der Code auf GitHub verfügbar.