IllegalMonitorStateException u Javi

1. Pregled

U ovom kratkom vodiču naučit ćemo o java.lang.IllegalMonitorStateException.

Stvorit ćemo jednostavnu aplikaciju pošiljatelja i primatelja koja donosi ovu iznimku. Zatim ćemo razgovarati o mogućim načinima sprečavanja. Na kraju ćemo pokazati kako pravilno implementirati ove klase pošiljatelja i primatelja.

2. Kada se baca?

The IllegalMonitorStateException vezan je uz programiranje više niti u Javi. Ako imamo a monitor želimo se sinkronizirati, ova se iznimka baca kako bi ukazala da je nit pokušala pričekati ili obavijestiti druge niti koje čekaju na tom monitoru, a da je ne posjedujemo. Jednostavnijim riječima, ovu ćemo iznimku dobiti ako pozovemo jednog od čekati(), obavijestiti(), ili notifyAll () metode Objekt razred izvan a sinkronizirano blok.

Izgradimo sada primjer koji baca znak IllegalMonitorStateException. Za ovo ćemo upotrijebiti oboje čekati() i notifyAll () metode za sinkronizaciju razmjene podataka između pošiljatelja i primatelja.

Prvo, pogledajmo Podaci razred koji sadrži poruku koju ćemo poslati:

podaci javne klase {poruka privatnog niza; public void send (String message) {this.message = message; } javni niz primanje () {povratna poruka; }}

Drugo, stvorimo klasu pošiljatelja koja baca IllegalMonitorStateException kad se zazove. U tu svrhu nazvat ćemo notifyAll () metoda bez umotavanja u a sinkronizirano blok:

klasa UnsynchronizedSender implementira Runnable {private static final Logger log = LoggerFactory.getLogger (UnsychronizedSender.class); privatni konačni podaci; javni UnsynchronizedSender (podaci podataka) {this.data = podaci; } @Override public void run () {try {Thread.sleep (1000); data.send ("test"); data.notifyAll (); } catch (InterruptedException e) {log.error ("nit je prekinuta", e); Thread.currentThread (). Interrupt (); }}}

Prijemnik će također baciti IllegalMonitorStateException. Slično prethodnom primjeru, uputit ćemo poziv na čekati() metoda izvan a sinkronizirano blok:

javna klasa UnsynchronizedReceiver implementira Runnable {private static final Logger log = LoggerFactory.getLogger (UnsynchronizedReceiver.class); privatni konačni podaci; privatna string poruka; javni nesinkronizirani primatelj (podaci podataka) {this.data = podaci; } @Override public void run () {try {data.wait (); this.message = data.receive (); } catch (InterruptedException e) {log.error ("nit je prekinuta", e); Thread.currentThread (). Interrupt (); }} javni String getMessage () {return poruka; }}

Na kraju, napravimo instanciranje obje klase i pošaljite poruku između njih:

javna praznina sendData () {Podaci podataka = novi Podaci (); UnsynchronizedReceiver receiver = novi UnsynchronizedReceiver (podaci); Thread receiverThread = nova nit (prijemnik, "prijemnik-nit"); receiverThread.start (); UnsynchronizedSender sender = novi UnsynchronizedSender (podaci); Nit senderThread = nova nit (pošiljatelj, "nit pošiljatelja"); senderThread.start (); senderThread.join (1000); receiverThread.join (1000); }

Kad pokušamo pokrenuti ovaj dio koda, primit ćemo IllegalMonitorStateException od oba Nesinkronizirani prijemnik i NesinkroniziraniPošiljatelj klase:

[sender-thread] POGREŠKA com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedSender - dogodila se ilegalna iznimka stanja monitora java.lang.IllegalMonitorStateException: null at java.base / java.lang.Object.notifyAll (Native Method) at com.baeldung.ex .illegalmonitorstate.UnsynchronizedSender.run (UnsynchronizedSender.java:15) na java.base / java.lang.Thread.run (Thread.java:844) [prijemnik-nit] GREŠKA com.baeldung.exceptions.illegalmonitorstate.Unsynchronized MonitorReceiver - nesinkronizirani monitorReceiver dogodila se iznimka stanja java.lang.IllegalMonitorStateException: null na java.base / java.lang.Object.wait (Native Method) na java.base / java.lang.Object.wait (Object.java:328) na com.baeldung. iznimke.illegalmonitorstate.UnsynchronizedReceiver.run (UnsynchronizedReceiver.java:12) na java.base / java.lang.Thread.run (Thread.java:844) 

3. Kako to popraviti

Da biste se riješili IllegalMonitorStateException, trebamo uputiti svaki poziv čekati(), obavijestiti(), i notifyAll () metode unutar a sinkronizirano blok. Imajući ovo na umu, pogledajmo kako se ispravno provodi Pošiljatelj čas bi trebao izgledati ovako:

klasa SynchronizedSender implementira Runnable {private final Data data; javni SynchronizedSender (podaci podataka) {this.data = podaci; } @Override public void run () {sinkronizirano (podaci) {data.send ("test"); data.notifyAll (); }}}

Imajte na umu da koristimo sinkronizirano blok na istom Podaci primjer kasnije nazivamo svojim notifyAll () metoda.

Popravimo Prijamnik na isti način:

klasa SynchronizedReceiver implementira Runnable {private static final Logger log = LoggerFactory.getLogger (SynchronizedReceiver.class); privatni konačni podaci; privatna string poruka; javni SynchronizedReceiver (podaci podataka) {this.data = podaci; } @Override public void run () {sinkronizirano (podaci) {try {data.wait (); this.message = data.receive (); } catch (InterruptedException e) {log.error ("nit je prekinuta", e); Thread.currentThread (). Interrupt (); }}} javni String getMessage () {return poruka; }}

Ako opet stvorimo obje klase i pokušamo poslati istu poruku između njih, sve funkcionira dobro, i nije izuzeta.

4. Zaključak

U ovom smo članku saznali što uzrokuje IllegalMonitorStateException i kako to spriječiti.

Kao i uvijek, kôd je dostupan na GitHub-u.