One Two Three
One Two Three

Reputation: 23497

put the current thread to sleep while waiting for another thread

At some point in my application, I want to put my main thread (ie., the currently executing thread) to sleep for some time or until the background has finished (and wakes it up), whichever comes first.

Here is what I did (which I thought would work, but didn't)

public static void main(String args[])
{
    // .... other stuff ...

    // show a splash screen
    // just think of this as an image
    showPlashScreen(): 
    new Thread(new Runnable()
    {
          public void run()
          {
                // do some work here

                // notify everyone after the work is done
                Thread.currentThread().notifyAll();
          }
    }).start();

    // now make the current thread to wait for the background
    // or for at most 1000
    Thread.currentThread().wait(1000);
    disposeSplashScreen();

    // ... other stuff ....
}

Executing this, I keep getting java.lang.IllegalMonitorStateException

(Partial) stacktrace:

Caused by: java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)

.... <cut> ....

Exception in thread "Thread-7" java.lang.IllegalMonitorStateException
    at java.lang.Object.notifyAll(Native Method)

Upvotes: 0

Views: 8286

Answers (4)

gprathour
gprathour

Reputation: 15333

As you want to put the current thread to sleep while waiting for another thread, the way you are doing it as of now is not meant for the same thing i.e. wait and notifiy methods.

These methods are meant to be used for Synchronized Objects not for thread.

For Threads you should use join method. Check Out

Upvotes: 0

SeniorJD
SeniorJD

Reputation: 7202

To be able to call notify() you need to synchronize on the same object.

synchronized (someObject) {
    someObject.wait();
}

/* different thread / object */
synchronized (someObject) {
    someObject.notify();
}

Upvotes: 5

JB Nizet
JB Nizet

Reputation: 691685

You're using two different objects for wait() and notifyAll() : the main thread waits on the main thread, whereas the background thread notifies on the background thread. You should use a shared, final object for the two calls. You should also wait and notify in a synchronized block on this shared object, as explained in the javadoc of those two methods. And there should only exit from the waiting state where some condition has changed, to avoid spurious wakeups, as explained in the javadoc.

But wait() and notifyAll() are too low-level and too hard to use correctly. You should use a higher-level abstraction like a Semaphore instead.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500225

Firstly, don't use wait and notify on Thread objects. That's used as an internal signalling channel, so your code can end up confusing the JRE code and vice versa.

Secondly, one reason it's not working is that your main thread is waiting on itself, and the background thread is notifying itself - those are different objects!

Thirdly, to use notify() and wait() you need to synchronize on the monitor first. Also, for wait you'd generally use a loop to check for a condition, to handle spurious wakeups.

Fourthly, if you're really waiting for a thread to end, you can just use join instead:

Thread thread = new Thread(new Runnable()
{
    @Override public void run()
    {
        // do some work here
    }
});
thread.start();

// Do something else

thread.join(1000);

(Unfortunately join doesn't indicate whether or not it returned due to a timeout or the thread completing - but you can check for the thread state afterwards.)

Alternatively, use one of the higher-level constructs in java.util.concurrent instead - they're generally less fiddly, as JB Nizet suggested.

Upvotes: 2

Related Questions