Java中的IllegalMonitorStateException

1.概述

在這個簡短的教程中,我們將學習java.lang.IllegalMonitorStateException.

我們將創建一個簡單的發送方-接收方應用程序,該應用程序將引發此異常。然後,我們將討論防止這種情況的可能方法。最後,我們將展示如何正確實現這些發送者和接收者類。

2.什麼時候拋出此異常?

IllegalMonitorStateException與Java中的多線程編程有關。如果我們有一個monitor ,則拋出此異常,以表明某個線程試圖等待,或者通知其他線程在該監視器上等待而不擁有它。用簡單的話來說,如果我們在synchronizedObject wait()notify(),notifyAll()方法之一,則會得到此異常。

現在讓我們構建一個拋出IllegalMonitorStateException的示例。為此,我們將同時使用wait()notifyAll()方法來同步發送方和接收方之間的數據交換。

首先,讓我們看一下保存將要發送的消息Data

public class Data {

 private String message;



 public void send(String message) {

 this.message = message;

 }



 public String receive() {

 return message;

 }

 }

其次,讓我們創建在被調用時IllegalMonitorStateException .為此,我們將調用notifyAll()方法,而不將其包裝在synchronized塊中:

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();

 }

 }

 }

接收者還將引發IllegalMonitorStateException.與前面的示例類似,我們將在synchronizedwait()

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;

 }

 }

最後,讓我們實例化這兩個類並在它們之間發送一條消息:

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);

 }

當我們嘗試運行這段代碼時,我們將同時從UnsynchronizedReceiverUnsynchronizedSenderIllegalMonitorStateException

[sender-thread] ERROR 1ju.org.exceptions.illegalmonitorstate.UnsynchronizedSender - illegal monitor state exception occurred

 java.lang.IllegalMonitorStateException: null


 at java.base/java.lang.Object.notifyAll(Native Method)


 at 1ju.org.exceptions.illegalmonitorstate.UnsynchronizedSender.run(UnsynchronizedSender.java:15)


 at java.base/java.lang.Thread.run(Thread.java:844)



 [receiver-thread] ERROR 1ju.org.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 1ju.org.exceptions.illegalmonitorstate.UnsynchronizedReceiver.run(UnsynchronizedReceiver.java:12)


 at java.base/java.lang.Thread.run(Thread.java:844)

3.如何修復

**要擺脫IllegalMonitorStateException,我們需要synchronized塊內進行wait()notify(),notifyAll()**考慮到這一點,讓我們看一下Sender類的正確實現應如何:

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();

 }

 }

 }

請注意,我們在Data synchronized塊,我們稍後將其稱為notifyAll()方法。

讓我們以相同的方式Receiver

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;

 }

 }

如果我們再次創建兩個類並嘗試在它們之間發送相同的消息,則一切正常,並且不會引發異常。

4 結論

在本文中,我們了解了導致IllegalMonitorStateException原因以及如何防止它。