本文分析一段旨在實現三個線程交替打印自身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