'CountDownLatch: object not locked by thread before wait()

I want to pause the main thread until the other thread finishes. I tried CountDownLatch and semaphore. but none of them worked. I got the same error for both.

Caused by: java.lang.IllegalMonitorStateException: object not locked by thread before wait()

Code

 public void testCountDownLatch(){
    final CountDownLatch countDownLatch = new CountDownLatch(1);
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                countDownLatch.countDown();
                //Toast.makeText(MainActivity.this, "Latch Released", Toast.LENGTH_SHORT).show();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();

    try {
        countDownLatch.wait();
        Toast.makeText(this, "Yes! I am free now", Toast.LENGTH_SHORT).show();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

I tried to search for a few hours and was able to understand the cause of the error (wait() won't know if the countdown() gets called before it, in that case it would wait forever) but I couldn't able to understand how to fix it:(



Solution 1:[1]

You are using the wrong method. You should call await, not wait. See CountDownLatch for example code.

Solution 2:[2]

You are calling the wrong method. You need to use await() instead of wait().

wait() is a method from Object and that method requires to synchronize over that object. Other synchronizers are normally preferred over Object#wait. Objects locked with Object#wait can be woken up with Object#notify or Object#notifyAll.

await() is a method of CountDownLatch and it waits for the CountDownLatch to count down (using CountDownLatch#countDown) to 0.

If you use Semaphore (basically the opposite of CountDownLatch), you can aquire (increase the count of the semaphore by 1 if its limit has not been reached yet) it with Semaphore#aquire and release (decrese the count of the semaphore) with Semaphore#release.

Aside from that, it seems like you are developing an Android app. You should never block the main thread of an Android application (or the UI thread of any graphical application) as this will block your UI and result in Application not responding notices. Blocking the UI (thread) means that your app will not respond to any UI events (like the user clivking on a button). If you need to do blocking stuff, you should do that in a background/worker thread. You should also refrain from doing IO operations in the main thread for that reason (android even blocks network operations in the main thread).

Solution 3:[3]

Conslution

You forgot to start the thread so the exception is so obvious.

object not locked by a thread before wait()

What happened is that wait() is called directly without calling countdown() method (since the thread was not started) so it throws IllegalMonitorStateException or else your program would be waiting for your whole life without letting you know.

Solution

Just call the start() method on the thread.

new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                countDownLatch.countDown();
                Toast.makeText(MainActivity.this, "Latch Released", Toast.LENGTH_SHORT).show();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();

Solution 4:[4]

1.The thread should start 2.It should be await and not wait.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ewramner
Solution 2 marc_s
Solution 3 ?????
Solution 4 marton