You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 20:14:54