多线程编程中使用wait方法导致IllegalMonitorStateException异常的原因是什么?

多线程编程中使用wait方法导致IllegalMonitorStateException异常的原因是什么?

线程编程中wait()方法抛出IllegalMonitorStateException异常的解析

本文分析一个多线程编程问题:三个线程(a、b、c)按顺序打印ID五次(abcabc…),使用wait()和notifyAll()方法同步,却抛出IllegalMonitorStateException异常。

问题描述: 程序使用volatile字符串变量current_thread控制线程执行顺序,并用synchronized块和wait()、notifyAll()方法进行同步。然而,运行时出现IllegalMonitorStateException。

错误代码片段:

// 线程打印完毕后,设置下一个要打印的线程标识,并唤醒其他线程 if (current_thread.equals("a")) {     current_thread = "b"; } else if (current_thread.equals("b")) {     current_thread = "c"; } else if (current_thread.equals("c")) {     current_thread = "a"; }

完整代码(略有修改,方便理解):

package 并发编程.work2;  public class Test {     private static volatile String current_thread = "A";     private static final Object lock = new Object();//新增锁对象      public static void main(String[] args) {         Thread t1 = new Thread(new PrintThreadName("A"), "A");         Thread t2 = new Thread(new PrintThreadName("B"), "B");         Thread t3 = new Thread(new PrintThreadName("C"), "C");         t1.start();         t2.start();         t3.start();     }      static class PrintThreadName implements Runnable {         private String threadName;          public PrintThreadName(String threadName) {             this.threadName = threadName;         }          @Override         public void run() {             for (int i = 0; i < 5; i++) {                 synchronized (lock) { // 使用独立锁对象                     while (!current_thread.equals(threadName)) {                         try {                             lock.wait(); // 使用独立锁对象                         } catch (InterruptedException e) {                             e.printStackTrace();                         }                     }                     System.out.print(threadName);                     if (threadName.equals("A")) {                         current_thread = "B";                     } else if (threadName.equals("B")) {                         current_thread = "C";                     } else {                         current_thread = "A";                     }                     lock.notifyAll(); // 使用独立锁对象                 }             }         }     } }

异常原因: wait()方法必须在持有对象的监视器锁时调用。 原代码中,current_thread作为锁对象,但在synchronized块内修改了current_thread的值。当线程调用wait()进入等待,current_thread的引用改变了。唤醒后,线程试图释放锁,但持有的锁对象已不是当前的current_thread,导致IllegalMonitorStateException。

解决方案: 使用一个独立的锁对象(例如代码中的lock对象)来控制线程同步,避免在持有锁的同时修改锁对象本身。 修改后的代码使用lock对象作为synchronized块的锁和wait()、notifyAll()方法的参数,从而避免了异常。 这保证了wait()方法始终在正确的锁对象上操作。

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享