使用ReentrantLock时wait()抛出IllegalMonitorStateException的原因探究
问题:ReentrantLock初始化方式引发IllegalMonitorStateException的原因分析
我运行第一段代码时触发了IllegalMonitorStateException异常,这段代码里ReentrantLock和Condition是作为类成员直接初始化的;但把这两个对象移到构造方法里初始化后,代码就能正常执行了。想搞明白这两种初始化方式的差异为啥会导致不同结果。
报错代码
static class PrintUseReentranLock implements Runnable{ ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); int n; int i; public PrintUseReentranLock(int n){ this.n = n; this.i = 0; } @Override public void run(){ while(i < n){ lock.lock(); condition.signal(); if(i%2==0) System.out.println("A"); else System.out.println("B"); i++; try { condition.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } condition.signal(); lock.unlock(); } } } @Test public void test2(){ PrintUseReentranLock p = new PrintUseReentranLock(10); Thread t1 = new Thread(p); Thread t2 = new Thread(p); t1.start(); t2.start(); }
报错信息
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread is not owner at java.base/java.lang.Object.wait(Native Method) at java.base/java.lang.Object.wait(Object.java:321) at ConsumerProductor.PrintUseLock$PrintUseReentranLock.run(PrintUseLock.java:96) at java.base/java.lang.Thread.run(Thread.java:832)
修改后可执行代码
static class PrintUseReentranLock implements Runnable{ ReentrantLock lock; Condition condition; int n; int i; public PrintUseReentranLock(int n){ this.n = n; this.i = 0; this.lock = new ReentrantLock(); this.condition = lock.newCondition(); } @Override public void run(){ while(i < n){ lock.lock(); condition.signal(); if(i%2==0) System.out.println("A"); else System.out.println("B"); i++; try { condition.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } condition.signal(); lock.unlock(); } } } @Test public void test2(){ PrintUseReentranLock p = new PrintUseReentranLock(10); Thread t1 = new Thread(p); Thread t2 = new Thread(p); t1.start(); t2.start(); }
问题根源与解释
首先明确:两种初始化方式本身没有本质差异——不管是在成员变量声明处直接初始化,还是在构造方法里初始化,最终同一个PrintUseReentranLock实例的lock和condition都是绑定的,且属于该实例私有,不会出现锁与条件对象不匹配的问题。
真正触发IllegalMonitorStateException的原因是方法误用:
- 你调用的
condition.wait()是Object类的内置方法,它要求当前线程必须持有condition对象的内置锁(即通过synchronized(condition)代码块获取锁),但你的代码里只通过lock.lock()获取了ReentrantLock的锁,并没有持有condition的内置锁,因此触发异常。 - 正确的做法是调用
Condition接口的await()方法,这个方法是和ReentrantLock配套设计的,只要求当前线程持有对应的ReentrantLock(也就是你已经通过lock.lock()获取的锁),完全匹配你的代码逻辑。
至于修改初始化方式后代码能执行,大概率是测试时的偶然情况,或是你在修改过程中不小心做了其他未提及的调整(比如误将wait()改成了await())。从逻辑上看,只要调用condition.wait(),不管哪种初始化方式,都会触发异常。
内容的提问来源于stack exchange,提问作者Yu Xing
相关产品推荐
相关产品推荐

