IllegalMonitorStateException:在wait()之前,线程未锁定对象

3

我知道有很多类似的问题,但没有一个能帮助我。 当我尝试暂停线程时,我会得到IllegalMonitorStateException: object not locked by thread before wait()

这是我的初始化方法:

// called only once in constructor; the variables are global ( private Thread ... )
    public void init() {

        recordingThread = new Thread(new Runnable() {
            @Override
            public void run() {
                isNewRecordingThread= false;
                record();
            }
        });

        recognitionThread = new Thread(new Runnable() {
            @Override
            public void run() {
                isNewRecognition= false;
                recognize();
            }
        });
...
}

startRecording 方法:

private synchronized void startRecording(Thread recordingThread) {
    if(isNewRecordingThread){
        recordingThread.start();
        return;
    }
    recordingThread.notify();
}

startRecognition方法:

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

我遇到错误的停止方法如下:

private synchronized void stopRecordingAndRecognition(Thread recordingThread, Thread recognitionThread) {
    try{
        if (recordingThread != null && recordingThread.isAlive()) {
            recordingThread.wait();
        }
        if (recognitionThread != null && recognitionThread.isAlive()) {
            recognitionThread.wait();
        }
    } catch (InterruptedException e){
        Log.d("TESTING","InterruptedException e= "+e);
    }
}

2
不建议在没有循环的情况下调用wait()/await(),因为这样可能会错过信号或出现虚假唤醒! - Mokarrom Hossain
有什么想法可以让它变得更好吗? - abrutsze
@abrutsze 如果我们不知道你想要实现什么,我们怎么能让它变得更好呢? - Alexei Kaigorodov
目标是启动线程,暂停它,然后恢复。 - abrutsze
@abrutsze,我已经添加了一个代码片段来暂停/恢复线程。 - Mokarrom Hossain
3个回答

1

目标是启动线程,暂停它,然后恢复

这是我用于暂停和恢复线程的代码片段。

public class ThreadStatus { 
    private boolean paused;
    private final String threadName;
    private final ReentrantLock lock;
    private final Condition condition;

    public ThreadStatus (String name) {
        threadName = name;
        lock = new ReentrantLock();
        condition = lock.newCondition();
        paused = false;
    }

    // check for the thread to be paused
    public void checkForPause() {
        lock.lock();
        try {
            while (paused) {                
                condition.await();
            }
        } catch (InterruptedException ie) {
            // interrupted
        } finally {
            lock.unlock();
        }
    }

    // Pause the thread
    public void pause() {
        lock.lock();
        try {
            paused = true;
        } finally {
            lock.unlock();
        }
    }

    // Resume the thread
    public void resume() {
        lock.lock();
        try {
            paused = false;
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public String toString() {
        return threadName;
    }
}

如果需要,您可以类似地实现 isStopped()isRunning()
final ThreadStatus threadStatus = new ThreadStatus("Thread-A");

在客户端代码中,在相关点调用threadStatus.checkForPause()。例如,如果您在循环内部有一些重复的处理过程,可以这样做 -
while (!threadStatus.isStopped()) {
      threadStatus.checkForPause();   

     // do your processing here
}

谢谢,我会检查的。 :) - abrutsze

1
"object not locked by thread before wait()"
“在wait()之前线程未锁定对象。”
思考一下,这个消息中指的是哪个对象?就是那个应用了wait()方法的对象。
recordingThread.wait();

那就是说,recordingThread 很重要。 synchronized void stopRecordingAndRecognition 不相关,因为它锁定了 this 对象,而不是 recordingThread。 因此,有两个解决方案:强制方法在 recordingThread 上同步,或将同步方法嵌入到 recordingThread 的类中。

1
请问您能否提供更多关于如何实现您的任何解决方案的信息? - abrutsze
@abrutsze,请查看我的另一个答案。 - Alexei Kaigorodov
这应该是被接受的答案,因为它解释了一个常见的错误。 :) - WebViewer

1

目标是启动线程,暂停它,然后恢复

在Java中暂停和恢复线程是一种不好的做法,因为会导致微妙且难以调试的错误。

唯一可靠的停止/恢复某个计算过程的方法是将该过程分成若干部分,在循环中处理这些部分,并在开始处理下一部分之前检查是否允许处理。

作为这种方法的演变,每个部分都形成一个Runnable并提交给单线程Executor。生产者线程只需停止和恢复向执行器提交部分任务,而不是停止和恢复Executor本身。

如果(某些)部分可以并行处理,则可以使用多线程执行器,但需要协调提交特定任务之间的顺序。


谢谢,我会检查的。 :) - abrutsze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接