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

线程暂停时触发IllegalMonitorStateException异常求助

解决IllegalMonitorStateException:线程暂停的正确姿势

这个问题我太熟悉了——你踩了Java中wait/notify机制的一个经典坑,咱们一步步拆解问题,再给出正确的实现方式。

为什么会抛出IllegalMonitorStateException?

你遇到的异常,核心问题是对wait()方法的理解完全搞反了:

  • wait()的作用是让当前执行该方法的线程进入等待状态,并且释放它持有的某个对象锁,而不是让你调用wait()的那个Thread对象暂停。
  • 调用wait()的前提是:当前线程必须持有该对象的监视器锁(也就是已经通过synchronized获取了这个对象的锁)。

看你的stopRecordingAndRecognition方法:

private synchronized void stopRecordingAndRecognition(Thread recordingThread, Thread recognitionThread) {
    try{
        if (recordingThread != null && recordingThread.isAlive()) {
            recordingThread.wait(); // 这里的核心问题!
        }
        // ...
    } catch (InterruptedException e){
        Log.d("TESTING","InterruptedException e= "+e);
    }
}

虽然方法是synchronized,但它锁的是当前类的实例对象(this),而不是recordingThread这个对象。你调用recordingThread.wait()时,当前线程并没有持有recordingThread的锁,所以JVM直接抛出IllegalMonitorStateException。

更重要的是:你想用recordingThread.wait()让录制线程暂停,这完全是方向错误——这只会让执行stop方法的线程等待,录制线程该跑还是跑。

正确的线程暂停实现方式

Java中控制线程暂停/恢复,推荐用标志位+专用锁对象的方式,而不是直接操作Thread对象的wait/notify(Thread对象的锁有JVM内部用途,不建议开发者直接使用)。

步骤1:定义全局控制变量

首先添加几个线程安全的控制变量和锁对象:

// 暂停标志位,用volatile保证多线程可见性
private volatile boolean isPausedRecording = false;
private volatile boolean isPausedRecognition = false;
// 专用锁对象,用于wait/notify逻辑
private final Object lockRecording = new Object();
private final Object lockRecognition = new Object();

// 保留你原来的变量
private Thread recordingThread;
private Thread recognitionThread;
private boolean isNewRecordingThread = true;
private boolean isNewRecognition = true;
private boolean shouldContinueRecognition = true;

步骤2:修改录制/识别的核心逻辑

在record()和recognize()方法中,加入暂停检查逻辑(假设这两个方法是循环执行任务的):

修改record()方法

private void record() {
    while (!Thread.currentThread().isInterrupted()) {
        // 检查是否需要暂停
        synchronized (lockRecording) {
            while (isPausedRecording) { // 用while防止虚假唤醒
                try {
                    lockRecording.wait(); // 当前录制线程进入等待
                } catch (InterruptedException e) {
                    // 恢复中断状态,让循环能正确退出
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }
        // 这里写你的录制逻辑
        // ...
    }
}

修改recognize()方法

private void recognize() {
    while (shouldContinueRecognition && !Thread.currentThread().isInterrupted()) {
        synchronized (lockRecognition) {
            while (isPausedRecognition) {
                try {
                    lockRecognition.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }
        // 这里写你的识别逻辑
        // ...
    }
}

步骤3:修改start/stop方法

现在更新你的启动和暂停方法,让它们正确控制标志位和唤醒线程:

修改startRecording方法

private void startRecording() {
    if (isNewRecordingThread) {
        recordingThread.start();
        isNewRecordingThread = false;
        return;
    }
    // 唤醒暂停的录制线程
    synchronized (lockRecording) {
        isPausedRecording = false;
        lockRecording.notify();
    }
}

修改startRecognition方法

private void startRecognition() {
    shouldContinueRecognition = true;
    if (isNewRecognition) {
        recognitionThread.start();
        isNewRecognition = false;
        return;
    }
    synchronized (lockRecognition) {
        isPausedRecognition = false;
        lockRecognition.notify();
    }
}

修改stopRecordingAndRecognition方法

private void stopRecordingAndRecognition() {
    // 标记录制线程为暂停状态
    synchronized (lockRecording) {
        isPausedRecording = true;
    }
    // 标记识别线程为暂停状态
    synchronized (lockRecognition) {
        isPausedRecognition = true;
    }
}

关键注意事项

  • 用volatile修饰标志位:确保多线程之间的状态可见性,避免线程读取到过期的标志值。
  • 用while循环检查标志位:防止虚假唤醒(JVM可能会在没有notify的情况下唤醒线程,while循环能再次确认状态)。
  • 不要直接操作Thread对象的锁:Thread对象的wait/notify是JVM内部用来实现join等功能的,开发者自定义逻辑应该用专用的锁对象。
  • 处理中断异常:当线程在wait时被中断,要恢复中断状态,让线程能正确响应终止信号。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:53:12