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

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

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

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

以下為問題代碼片段:

package 并發編程.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();                 }             }         }     } }

異常原因分析:

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

解決方案:

避免在釋放鎖之前修改鎖對象本身。應使用一個獨立的、不會被修改的對象作為鎖,例如一個Object實例。這樣確保所有線程都在同一個鎖對象上進行同步操作,避免IllegalMonitorStateException異常。 修改后的代碼如下:

package 并發編程.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) { // 使用獨立的鎖對象LOCK                     while (!Thread.currentThread().getName().equals(CURRENT_THREAD)) {                         try {                             LOCK.wait(); // 在LOCK對象上等待                         } 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對象上喚醒                 }             }         }     } }

通過使用獨立的鎖對象LOCK,解決了IllegalMonitorStateException異常,并保證了線程的正確同步。

? 版權聲明
THE END
喜歡就支持一下吧
點贊6 分享