多線程同步中wait()方法導(dǎo)致IllegalMonitorStateException異常的原因是什么?

多線程同步中wait()方法導(dǎo)致IllegalMonitorStateException異常的原因是什么?

線程同步與wait()方法異常詳解

本文分析一段旨在實(shí)現(xiàn)三個(gè)線程交替打印自身ID的代碼,并解釋其中出現(xiàn)的IllegalMonitorStateException異常。該代碼嘗試使用共享字符串變量current_thread控制線程執(zhí)行順序,但由于不當(dāng)使用wait()和notifyAll()方法導(dǎo)致錯(cuò)誤。

以下為問(wèn)題代碼片段:

package 并發(fā)編程.work2;  public class Test {     private static volatile String CURRENT_THREAD = "A";      public static void main(String[] args) {         Thread t1 = new Thread(new PrintThreadName(), "A");         Thread t2 = new Thread(new PrintThreadName(), "B");         Thread t3 = new Thread(new PrintThreadName(), "C");         t1.start();         t2.start();         t3.start();     }      static class PrintThreadName implements Runnable {         @Override         public void run() {             for (int i = 0; i < 10; i++) {                 synchronized (CURRENT_THREAD) {                     while (!Thread.currentThread().getName().equals(CURRENT_THREAD)) {                         try {                             CURRENT_THREAD.wait();                         } catch (InterruptedException e) {                             e.printStackTrace();                         }                     }                     System.out.println(Thread.currentThread().getName() + ":" + i);                     CURRENT_THREAD = CURRENT_THREAD.equals("A") ? "B" : (CURRENT_THREAD.equals("B") ? "C" : "A");                     CURRENT_THREAD.notifyAll();                 }             }         }     } }

異常原因分析:

代碼的核心問(wèn)題在于current_thread變量的用法。代碼試圖將current_thread用作鎖對(duì)象,并在持有鎖的同時(shí)修改其值。當(dāng)一個(gè)線程執(zhí)行current_thread.wait()進(jìn)入等待狀態(tài)后,另一個(gè)線程修改了current_thread的值。等待線程被喚醒后,它試圖在新的current_thread對(duì)象上釋放鎖,而這個(gè)對(duì)象并非它之前獲取鎖的對(duì)象,因此拋出IllegalMonitorStateException異常。wait()方法要求在持有鎖對(duì)象的線程上調(diào)用,而修改current_thread后,鎖對(duì)象已改變。

解決方案:

避免在釋放鎖之前修改鎖對(duì)象本身。應(yīng)使用一個(gè)獨(dú)立的、不會(huì)被修改的對(duì)象作為鎖,例如一個(gè)Object實(shí)例。這樣確保所有線程都在同一個(gè)鎖對(duì)象上進(jìn)行同步操作,避免IllegalMonitorStateException異常。 修改后的代碼如下:

package 并發(fā)編程.work2;  public class Test {     private static final Object LOCK = new Object();     private static volatile String CURRENT_THREAD = "A";      public static void main(String[] args) {         // ... (rest of the main method remains the same)     }      static class PrintThreadName implements Runnable {         @Override         public void run() {             for (int i = 0; i < 10; i++) {                 synchronized (LOCK) { // 使用獨(dú)立的鎖對(duì)象LOCK                     while (!Thread.currentThread().getName().equals(CURRENT_THREAD)) {                         try {                             LOCK.wait(); // 在LOCK對(duì)象上等待                         } catch (InterruptedException e) {                             e.printStackTrace();                         }                     }                     System.out.println(Thread.currentThread().getName() + ":" + i);                     CURRENT_THREAD = CURRENT_THREAD.equals("A") ? "B" : (CURRENT_THREAD.equals("B") ? "C" : "A");                     LOCK.notifyAll(); // 在LOCK對(duì)象上喚醒                 }             }         }     } }

通過(guò)使用獨(dú)立的鎖對(duì)象LOCK,解決了IllegalMonitorStateException異常,并保證了線程的正確同步。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊6 分享