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

Java wait/notify实现奇偶交替打印报IllegalMonitorStateException问题

问题解答
  • 不存在“for循环中不允许使用synchronized块”的限制,你遇到的异常和synchronized块的位置无关。
  • IllegalMonitorStateException的触发原因非常明确:调用对象的wait()/notify()/notifyAll()方法时,当前线程没有持有该对象的监视器锁。

根因细节

你的代码中自定义了专门的锁对象private Object lock = new Object();,同步块也确实是对lock加锁:

synchronized (lock){
    // 临界区代码
}

但你在临界区内直接调用了无前缀的wait()和notifyAll(),这种写法等价于调用this.wait()和this.notifyAll()——也就是你尝试操作的是当前OddEvenPrinter实例的等待队列,但你持有的是lock对象的锁,从来没有获取过当前实例的监视器锁,自然会抛出非法监视器状态异常。

Java 多线程 wait/notify 机制的强制规则:任何对象的wait、notify、notifyAll方法,都必须在持有该对象自身监视器锁的上下文(即synchronized(该对象)修饰的代码块/方法)中调用,否则直接抛出IllegalMonitorStateException。

额外隐藏问题

你的代码除了wait/notify调用对象错误之外,还有一处逻辑漏洞会导致无法实现交替打印:打印完成、唤醒等待线程前,没有切换printFlag标志位的状态。就算修正了锁调用问题,打印完奇数后printFlag仍为false,下一轮循环奇数线程不会进入等待状态,会连续打印奇数,完全达不到交替效果。

修正后可运行代码

public class OddEvenPrinter {
    private Object lock = new Object();
    private boolean printFlag = false;

    void printOdd() throws InterruptedException {
        for(int i=1; i < 25; i=i+2){
            synchronized (lock){
                while(printFlag){
                    // 调用当前持有锁的lock对象的wait方法
                    lock.wait();
                }
                System.out.println(i + "********  PRINT ODD  ");
                // 切换标志位,标记下次该打印偶数
                printFlag = true;
                // 唤醒在lock对象上等待的偶数打印线程
                lock.notifyAll();
            }
        }
    }

    void printEven() throws InterruptedException {
        for(int i=0; i < 25; i=i+2){
            synchronized (lock){
                while(!printFlag){
                    lock.wait();
                }
                System.out.println(i + "********  PRINT EVEN  ");
                // 切换标志位,标记下次该打印奇数
                printFlag = false;
                lock.notifyAll();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        OddEvenPrinter printer = new OddEvenPrinter();
        Thread a = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    printer.printEven();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        Thread b = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    printer.printOdd();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        a.start();
        b.start();
        // 等待两个工作线程执行完成再打印结束提示
        a.join();
        b.join();
        System.out.println("All DONE.....");
    }
}

内容的提问来源于stack exchange,提问作者Vineel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 21:18:55