IllegalMonitorStateException v Jave

1. Prehľad

V tomto krátkom návode sa dozvieme niečo o java.lang.IllegalMonitorStateException.

Vytvoríme jednoduchú aplikáciu odosielateľ-príjemca, ktorá spôsobí túto výnimku. Potom prediskutujeme možné spôsoby, ako tomu zabrániť. Na záver si ukážeme, ako správne implementovať tieto triedy odosielateľa a prijímača.

2. Kedy sa hodí?

The IllegalMonitorStateException súvisí s programovaním viacerých vlákien v Jave. Ak máme a monitor chceme synchronizovať ďalej, táto výnimka je vyvolaná, aby naznačila, že sa vlákno pokúsilo čakať, alebo aby upozornilo ďalšie vlákna čakajúce na tomto monitore bez toho, aby ho vlastnilo. Jednoduchšie povedané, túto výnimku dostaneme, ak zavoláme jednu z počkaj (), upozorniť (), alebo notifyAll () metódy Objekt trieda mimo a synchronizované blokovať.

Poďme si teraz zostaviť príklad, ktorý hodí IllegalMonitorStateException. Na to použijeme oboje počkaj () a notifyAll () metódy synchronizácie výmeny údajov medzi odosielateľom a prijímateľom.

Najskôr sa pozrime na Údaje trieda, ktorá obsahuje správu, ktorú pošleme:

public class Data {private String message; public void send (String message) {this.message = správa; } public String receive () {spätna sprava; }}

Po druhé, vytvorme triedu odosielateľa, ktorá hodí IllegalMonitorStateException pri vyvolaní. Z tohto dôvodu budeme nazývať notifyAll () metóda bez toho, aby to bolo zabalené do a synchronizované blok:

trieda UnsynchronizedSender implementuje Runnable {private static final Logger log = LoggerFactory.getLogger (UnsychronizedSender.class); súkromné ​​konečné údaje; 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 ("vlákno bolo prerušené", e); Thread.currentThread (). Interrupt (); }}}

Prijímač sa tiež chystá hodiť IllegalMonitorStateException. Podobne ako v predchádzajúcom príklade, zavoláme na počkaj () metóda mimo a synchronizované blok:

verejná trieda UnsynchronizedReceiver implementuje Runnable {private static final Logger log = LoggerFactory.getLogger (UnsynchronizedReceiver.class); súkromné ​​konečné údaje; súkromná reťazcová správa; public UnsynchronizedReceiver (údajové údaje) {this.data = údaje; } @Override public void run () {try {data.wait (); this.message = data.receive (); } catch (InterruptedException e) {log.error ("vlákno bolo prerušené", e); Thread.currentThread (). Interrupt (); }} public String getMessage () {spätna sprava; }}

Na záver vytvoríme inštancie oboch tried a pošleme im správu:

public void sendData () {Data data = new Data (); Prijímač UnsynchronizedReceiver = nový UnsynchronizedReceiver (dáta); Thread receiverThread = new Thread (receiver, "receiver-thread"); receiverThread.start (); UnsynchronizedSender sender = nový UnsynchronizedSender (dáta); Thread senderThread = new Thread (sender, "sender-thread"); senderThread.start (); senderThread.join (1000); receiverThread.join (1000); }

Keď sa pokúsime spustiť tento kód, dostaneme IllegalMonitorStateException od oboch UnsynchronizedReceiver a UnsynchronizedSender triedy:

[sender-thread] CHYBA com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedSender - došlo k výnimke stavu nelegálneho monitora java.lang.IllegalMonitorStateException: null na java.base / java.lang.Object.notifyAll (natívna metóda) na com.baeldung.exceptions .illegalmonitorstate.UnsynchronizedSender.run (UnsynchronizedSender.java:15) na java.base / java.lang.Thread.run (Thread.java:844) [receiver-thread] CHYBA com.baeldung.exceptions.illegalmonitorstate.UnsynchronizedReceiver - nelegálny monitor došlo k štátnej výnimke java.lang.IllegalMonitorStateException: null na java.base / java.lang.Object.wait (natívna metóda) na java.base / java.lang.Object.wait (Object.java:328) na com.baeldung. exceptions.illegalmonitorstate.UnsynchronizedReceiver.run (UnsynchronizedReceiver.java:12) na adrese java.base / java.lang.Thread.run (Thread.java:844) 

3. Ako to opraviť

Zbaviť sa IllegalMonitorStateException, musíme uskutočniť každé volanie počkaj (), upozorniť (), a notifyAll () metódy v rámci a synchronizované blokovať. V tejto súvislosti sa pozrime, ako sa správne implementuje Odosielateľ trieda by mala vyzerať takto:

trieda SynchronizedSender implementuje Runnable {private final Data data; public SynchronizedSender (údaje): {this.data = údaje; } @Override public void run () {synchronized (data) {data.send ("test"); data.notifyAll (); }}}

Všimnite si, že používame synchronizované blok na rovnakom Údaje inštanciu, ktorú neskôr nazveme jeho notifyAll () metóda.

Poďme opraviť Prijímač rovnakym sposobom:

trieda SynchronizedReceiver implementuje Runnable {private static final Logger log = LoggerFactory.getLogger (SynchronizedReceiver.class); súkromné ​​konečné údaje; súkromná reťazcová správa; 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 ("vlákno bolo prerušené", e); Thread.currentThread (). Interrupt (); }}} public String getMessage () {spätna sprava; }}

Ak opäť vytvoríme obe triedy a pokúsime sa medzi nimi poslať tú istú správu, všetko funguje dobre a nehrozí žiadna výnimka.

4. Záver

V tomto článku sme sa dozvedeli, čo spôsobuje IllegalMonitorStateException a ako tomu zabrániť.

Ako vždy, kód je k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found