abrutsze
abrutsze

Reputation: 506

IllegalMonitorStateException: object not locked by thread before wait()

I know that there are a lot of similar questions, but no one helped me. I am getting IllegalMonitorStateException: object not locked by thread before wait() when I try to pause the thread.

Here is my initialization method:

// 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 method:

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

startRecognition method:

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

And the stopping method where I actually get the error:

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);
    }
}

Upvotes: 3

Views: 5080

Answers (3)

Mokarrom Hossain
Mokarrom Hossain

Reputation: 377

The goal is to start thread, pause it and after resume

Here is a code snippet that I use for suspending and resuming a thread.

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;
    }
}

If you need you could implement isStopped() or isRunning() similarly.

final ThreadStatus threadStatus = new ThreadStatus("Thread-A");

In the client code, call threadStatus.checkForPause() at the relevant point. For example, if you have some repeated processings inside a loop, you can do something like -

while (!threadStatus.isStopped()) {
      threadStatus.checkForPause();   

     // do your processing here
}

Upvotes: 1

Alexei Kaigorodov
Alexei Kaigorodov

Reputation: 13525

"The goal is to start thread, pause it and after resume"

Pausing and resuming threads in Java is a bad practice because leads to subtle and hard to debug errors.

The only reliable way to stop/resume some computational process is to split this process into parts, process that parts in a loop, and before the start of processing the next part, checking if processing is allowed.

As an evolution of this approach, each part is formed as a Runnable and is submitted to a single-threaded Executor. Instead of stop and resume the Executor, producer thread(s) simply stop and resume submitting the partial tasks to the executor.

If (some) parts can be processed in parallel, then multithreaded executor can be used, but it requires coordination between submitting particular tasks.

Upvotes: 1

Alexei Kaigorodov
Alexei Kaigorodov

Reputation: 13525

"object not locked by thread before wait()"

Think, what object is meant in this message? That very object for which wait() is applied:

recordingThread.wait();

that is, recordingThread.

synchronized void stopRecordingAndRecognition is irrelevant because it locks this object, and not recordingThread.

So, there are 2 solutions:

  • force methods to synchronize on recordingThread
  • embed synchronized methods into the class of recordingThread

Upvotes: 1

Related Questions