IllegalMonitorStateException Java-ban

1. Áttekintés

Ebben a rövid bemutatóban megismerjük java.lang.IllegalMonitorStateException.

Létrehozunk egy egyszerű feladó-vevő alkalmazást, amely ezt a kivételt elveti. Ezután megvitatjuk a megelőzés lehetséges módjait. Végül megmutatjuk, hogyan lehet ezeket a küldő és vevő osztályokat helyesen megvalósítani.

2. Mikor dobják?

A IllegalMonitorStateException a Java többszálas programozásához kapcsolódik. Ha van egy monitor szeretnénk tovább szinkronizálni, ez a kivétel annak jelzésére szolgál, hogy egy szál várakozással próbálkozott, vagy a monitoron várakozó többi szálat értesítette anélkül, hogy birtokolta volna. Egyszerűbb szavakkal megkapjuk ezt a kivételt, ha meghívjuk az egyiket várjon(), értesít (), vagy értesítMinden () módszerei Tárgy osztályon kívül a szinkronizált Blokk.

Készítsünk most egy példát, amely egy IllegalMonitorStateException. Ehhez mindkettőt használni fogjuk várjon() és értesítMinden () módszerek a feladó és a vevő közötti adatcsere szinkronizálására.

Először nézzük meg a Adat osztály, amely az üzenetet fogja küldeni:

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

Másodsorban hozzuk létre a küldő osztályt, amely egy IllegalMonitorStateException amikor felhívják. Erre a célra hívjuk a értesítMinden () módszer anélkül, hogy a szinkronizált Blokk:

class UnsynchronizedSender megvalósítja a Runnable {private static final Logger log = LoggerFactory.getLogger (UnsychronizedSender.class); magán végső adatok; public UnsynchronizedSender (Data data) {this.data = adatok; } @Orride public void run () {try {Thread.sleep (1000); data.send ("teszt"); data.notifyAll (); } catch (InterruptedException e) {log.error ("a szál megszakadt", e); Thread.currentThread (). Megszakítás (); }}}

A vevő is dobni fog egy IllegalMonitorStateException. Az előző példához hasonlóan felhívjuk a várjon() módszer a szinkronizált Blokk:

public class UnsynchronizedReceiver megvalósítja a Runnable {private static final Logger log = LoggerFactory.getLogger (UnsynchronizedReceiver.class); magán végső adatok; privát karakterlánc üzenet; public UnsynchronizedReceiver (Data data) {this.data = adatok; } @Orride public void run () {try {data.wait (); this.message = data.receive (); } catch (InterruptedException e) {log.error ("a szál megszakadt", e); Thread.currentThread (). Megszakítás (); }} public String getMessage () {return üzenet; }}

Végül példázzuk mindkét osztályt, és küldjünk üzenetet közöttük:

public void sendData () {Data data = new Data (); UnsynchronizedReceiver vevő = új UnsynchronizedReceiver (adatok); Thread receiverThread = új szál (vevő, "vevő-szál"); receiverThread.start (); UnsynchronizedSender sender = új UnsynchronizedSender (adatok); Thread senderThread = új szál (sender, "sender-thread"); senderThread.start (); senderThread.join (1000); receiverThread.join (1000); }

Amikor megpróbáljuk futtatni ezt a kóddarabot, kapunk egy IllegalMonitorStateException mindkettőtől UnsynchronizedReceiver és UnsynchronizedSender osztályok:

[sender-thread] ERROR com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedSender - illegális monitorállapot-kivétel történt java.lang.IllegalMonitorStateException: null at java.base / java.lang.Object.notifyAll (natív módszer) at com.baeldung.exceptions .illegalmonitorstate.UnsynchronizedSender.run (UnsynchronizedSender.java:15) a java.base / java.lang.Thread.run (Thread.java:844) [vevő-szál] ERROR com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedReceiver - illegális monitor állapot kivétel történt java.lang.IllegalMonitorStateException: null a java.base / java.lang.Object.wait (natív módszer) a java.base / java.lang.Object.wait (Object.java:328) com.baeldung címen Kivételek.illegalmonitorstate.UnsynchronizedReceiver.run (UnsynchronizedReceiver.java:12) itt: java.base / java.lang.Thread.run (Thread.java:844) 

3. Hogyan lehet kijavítani

Megszabadulni a IllegalMonitorStateException, minden hívást meg kell tennünk várjon(), értesít (), és értesítMinden () módszerek a szinkronizált Blokk. Ezt szem előtt tartva nézzük meg, hogy a Feladó osztálynak kell kinéznie:

class SynchronizedSender megvalósítja a Runnable {private final Data data; public SynchronizedSender (Data data) {this.data = adatok; } @Orride public void run () {synchronized (data) {data.send ("test"); data.notifyAll (); }}}

Ne feledje, hogy a szinkronizált blokk ugyanazon Adat példányt később annak hívjuk értesítMinden () módszer.

Javítsuk ki a Vevő ugyanúgy:

class SynchronizedReceiver megvalósítja a Runnable {private static final Logger log = LoggerFactory.getLogger (SynchronizedReceiver.class); magán végső adatok; privát karakterlánc üzenet; public SynchronizedReceiver (Data data) {this.data = adatok; } @Orride public void run () {synchronized (data) {try {data.wait (); this.message = data.receive (); } catch (InterruptedException e) {log.error ("a szál megszakadt", e); Thread.currentThread (). Megszakítás (); }}} public String getMessage () {return üzenet; }}

Ha újra létrehozzuk mindkét osztályt, és megpróbáljuk ugyanazt az üzenetet elküldeni közöttük, akkor minden jól működik, és ez alól nincs kivétel.

4. Következtetés

Ebben a cikkben megtudtuk, mi okozza IllegalMonitorStateException és hogyan lehet megakadályozni.

Mint mindig, a kód elérhető a GitHubon.