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

使用两个线程打印奇偶数字时抛出IllegalMonitorStateException问题排查

问题分析与解决方案

兄弟,你遇到的IllegalMonitorStateException是线程同步里的典型坑,我来给你拆解问题出在哪,再给你修正后的代码:

为什么会抛出这个异常?

这个异常的核心原因很明确:当你调用wait()、notify()或notifyAll()方法时,当前线程并没有持有该对象的监视器锁——简单说就是你没在synchronized块/方法里操作这个对象,就敢调用这些需要锁权限的方法。

结合你给出的代码片段,大概率踩了这两个坑:

  • 用了Boolean evenFlag或者Integer sharedCount作为锁对象,但这俩都是不可变类型。比如你执行evenFlag = !evenFlag时,会生成一个新的Boolean对象,后续的synchronized块就会锁定不同的对象,导致wait/notify时的锁完全不匹配。
  • 可能你的synchronized块锁定的对象,和调用wait/notify的对象不是同一个;甚至直接在无锁保护的地方调用了wait/notify。

修正后的代码示例

我给你调整了代码,用专门的共享锁对象来做同步,同时修正了线程间的协作逻辑:

package com.rishi.threading;

public class OddEvenPrinter {
    // 用一个专门的、可变的锁对象,彻底避免不可变类型的坑
    private final Object lock = new Object();
    private int sharedCount = 1;
    private static final int MAX_NUM = 20; // 打印到20为止

    // 打印奇数的线程
    class OddThread extends Thread {
        @Override
        public void run() {
            while (sharedCount <= MAX_NUM) {
                synchronized (lock) {
                    // 当当前数是偶数时,等待偶数线程处理完
                    while (sharedCount % 2 == 0) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }
                    // 打印奇数并自增
                    System.out.println("奇数线程输出: " + sharedCount);
                    sharedCount++;
                    // 通知偶数线程可以工作了
                    lock.notify();
                }
            }
        }
    }

    // 打印偶数的线程
    class EvenThread extends Thread {
        @Override
        public void run() {
            while (sharedCount <= MAX_NUM) {
                synchronized (lock) {
                    // 当当前数是奇数时,等待奇数线程处理完
                    while (sharedCount % 2 != 0) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }
                    // 打印偶数并自增
                    System.out.println("偶数线程输出: " + sharedCount);
                    sharedCount++;
                    // 通知奇数线程可以工作了
                    lock.notify();
                }
            }
        }
    }

    public static void main(String[] args) {
        OddEvenPrinter printer = new OddEvenPrinter();
        printer.new OddThread().start();
        printer.new EvenThread().start();
    }
}

关键修正点说明

  • 用专门的锁对象:创建了一个Object lock作为共享锁,它是可变的,不会因为值的变化变成新对象,确保所有线程都锁定同一个对象。
  • 锁内调用wait/notify:所有的wait()和notify()都在synchronized(lock)的保护下执行,保证当前线程持有锁权限。
  • 用while循环判断条件:避免线程被虚假唤醒(线程被唤醒后,条件可能已经变化,必须重新检查)。
  • 抛弃不可变锁对象:Integer、Boolean这类不可变类型,每次赋值都会生成新对象,绝对不能用来做同步锁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:59:25