views:

453

answers:

5

I am using multi-threading in java for my program. I have run thread successfully but when I am using Thread.wait(), it is throwing java.lang.IllegalMonitorStateException. How can I make a thread wait until it will be notified?

+9  A: 

You need to be in a synchronized block in order for Object.wait() to work.

Also, I recommend looking at the concurrency packages instead of the old school threading packages. They are safer and way easier to work with.

Happy coding.

EDIT

I assumed you meant Object.wait() as your exception is what happens when you try to gain access without holding the objects lock.

reccles
`Thread.wait`?!
Tom Hawtin - tackline
good catch. i assumed he meant Object.wait() and called from a thread
reccles
A: 

Since you haven't posted code, we're kind of working in the dark. What are the details of the exception?

Are you calling Thread.wait() from within the thread, or outside it?

I ask this because according to the javadoc for IllegalMonitorStateException, it is:

Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.

To clarify this answer, this call to wait on a thread also throws IllegalMonitorStateException, despite being called from within a synchronized block:


     private static final class Lock { }
     private final Object lock = new Lock();

    @Test
    public void testRun() {
        ThreadWorker worker = new ThreadWorker();
        System.out.println ("Starting worker");
        worker.start();
        System.out.println ("Worker started - telling it to wait");
        try {
            synchronized (lock) {
                worker.wait();
            }
        } catch (InterruptedException e1) {
            String msg = "InterruptedException: [" + e1.getLocalizedMessage() + "]";
            System.out.println (msg);
            e1.printStackTrace();
            System.out.flush();
        }
        System.out.println ("Worker done waiting, we're now waiting for it by joining");
        try {
            worker.join();
        } catch (InterruptedException ex) { }

    }
CPerkins
@CPerkins: I think you're confusing the execution thread and the object which is the target of `wait()`.
Robert Munteanu
@Robert - Perhaps I am, but I don't think so. If you start a Thread instance, and then ask it to wait, you'll get an IllegalMonitorStateException, which is what I was attempting to describe.
CPerkins
Are you talking about the `worker.wait()` line? Then you should be synchronizing on the worker, not on the lock.
Robert Munteanu
Good point, thanks. That works.
CPerkins
+1  A: 

wait is defined in Object not Thread. The monitor on Thread is a little unpredictable.

Although all Java objects have monitors, it generally better to have a dedicated lock:

 private final Object lock = new Object();

You can get slightly easier to read diagnostics, at a small memory cost (about 2K per process) by using a named class:

 private static final class Lock { }
 private final Object lock = new Lock();

In order to wait or notify/notifyAll an object, you need to be holding the lock with the synchronized statement. Also, you will need a while loop to check for the wakeup condition (find a good text on threading to explain why).

 synchronized (lock) {
      while (!isWakeupNeeded()) {
          lock.wait();
      }
 }

To notify:

 synchronized (lock) {
     makeWakeupNeeded();
     lock.notifyAll();
 }

It is well worth getting to understand both Java language and java.util.concurrent.locks locks (and java.util.concurrent.atomic) when getting into multithreading. But use java.util.concurrent data structures whenever you can.

Tom Hawtin - tackline
A: 

Thread.wait() call make sense inside a code that synchronizes on Thread.class object. I don't think it's what you meant.
You ask

How can I make a thread wait until it will be notified?

You can make only your current thread wait. Any other thread can be only gently asked to wait, if it agree.
If you want to wait for some condition, you need a lock object - Thread.class object is a very bad choice - it is a singleton AFAIK so synchronizing on it (except for Thread static methods) is dangerous.
Details for synchronization and waiting are already explained by Tom Hawtin. java.lang.IllegalMonitorStateException means you are trying to wait on object on which you are not synchronized - it's illegal to do so.

Tadeusz Kopec
A: 

Based on your comments it sounds like you are doing something like this:

Thread thread = new Thread(new Runnable(){
    public void run() { // do stuff }});

thread.start();
...
thread.wait();

There are two problems. First, as others have said, obj.wait() can only be called if the current thread holds the primitive mutex for obj. If the current thread does not hold the mutex, you get the exception you are seeing.

The second (more important) problem is that thread.wait() does not do what you seem to be expecting it to do. Specifically, thread.wait() does not cause the nominated thread to wait. Rather it causes the current thread to wait until some other thread calls thread.notify() or thread.notifyAll().

There is actually no safe way to force a Thread instance to pause if it doesn't want to. (The nearest that Java has to this is the deprecated Thread.suspend() method, but that method is inherently unsafe, as is explained in the Javadoc.)

If you want the newly started Thread to pause, the best way to do it is to create a CountdownLatch instance and have the thread call await() on the latch to pause itself. The main thread would then call countDown() on the latch to let the paused thread continue.

Stephen C