IllegalMonitorStateException di Java

1. Ikhtisar

Dalam tutorial singkat ini, kita akan belajar tentang java.lang.IllegalMonitorStateException.

Kami akan membuat aplikasi pengirim-penerima sederhana yang menampilkan pengecualian ini. Kemudian, kami akan membahas kemungkinan cara mencegahnya. Terakhir, kami akan menunjukkan cara mengimplementasikan kelas pengirim dan penerima ini dengan benar.

2. Kapan Itu Dilempar?

The IllegalMonitorStateException berhubungan dengan multithreading pemrograman di Jawa. Jika kita memiliki monitor yang ingin kita sinkronkan, pengecualian ini ditampilkan untuk menunjukkan bahwa utas mencoba menunggu atau memberi tahu utas lain yang menunggu di monitor itu, tanpa memilikinya. Dengan kata yang lebih sederhana, kita akan mendapatkan pengecualian ini jika kita memanggil salah satu metode wait () , notify (), atau notifyAll () dari kelas Object di luar blok yang disinkronkan .

Sekarang mari kita buat contoh yang menampilkan IllegalMonitorStateException . Untuk ini, kita akan menggunakan metode wait () dan notifyAll () untuk menyinkronkan pertukaran data antara pengirim dan penerima.

Pertama, mari kita lihat kelas Data yang menyimpan pesan yang akan kita kirim:

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

Kedua, mari buat kelas pengirim yang menampilkan IllegalMonitorStateException saat dipanggil . Untuk tujuan ini, kita akan memanggil metode notifyAll () tanpa membungkusnya dalam blok tersinkronisasi :

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

Penerima juga akan menampilkan IllegalMonitorStateException. Mirip dengan contoh sebelumnya, kita akan membuat panggilan ke metode wait () di luar blok yang disinkronkan :

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

Terakhir, mari kita buat kedua kelas dan mengirim pesan di antara keduanya:

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

Ketika kita mencoba untuk menjalankan potongan kode ini, kita akan menerima IllegalMonitorStateException dari kedua UnsynchronizedReceiver dan UnsynchronizedSender kelas:

[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. Bagaimana Memperbaikinya

Untuk menyingkirkan IllegalMonitorStateException, kita perlu melakukan setiap panggilan ke metode wait () , notify (), dan notifyAll () dalam blok yang disinkronkan . Dengan pemikiran ini, mari kita lihat bagaimana implementasi yang benar dari kelas Pengirim akan terlihat:

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

Perhatikan bahwa kami menggunakan blok tersinkronisasi pada instance Data yang sama yang kemudian kami sebut metode notifyAll () .

Mari perbaiki Penerima dengan cara yang sama:

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

Jika kita kembali membuat kedua kelas dan mencoba mengirim pesan yang sama di antara mereka, semuanya bekerja dengan baik, dan tidak terkecuali dilempar.

4. Kesimpulan

Di artikel ini, kami mempelajari apa yang menyebabkan IllegalMonitorStateException dan cara mencegahnya.

Seperti biasa, kode tersedia di GitHub.