线程暂停时触发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
相关产品推荐
相关产品推荐

