I am playing around with the timed version of wait() in java.lang.Object and have observed that it acts differently in two different scenarios.
Scenario1: Using the default definition of run() in Thread
public static void main (String[] args) throws InterruptedException {
Thread t = new Thread();
t.start();
System.out.print("X");
synchronized(t) { t.wait(10000);}
System.out.print("Y");
}
Questions on scenario1: I am experiencing a delay between X and Y. Is this because I am calling wait() from main (even though, on t) and therefore the call stack of the main thread is being used, rather than that of the second thread?
Scenario2: Subclassing Thread on-the-fly to override run() in order to print something.
public static void main (String[] args) throws InterruptedException {
Thread t = new Thread() {public void run()
{System.out.print("I am the second thread.");}};
t.start();
System.out.print("X");
synchronized(t) { t.wait(10000);}
System.out.print("Y");
}
Questions on scenario2: I am NOT experiencing any delay at all! What has changed just because I have overridden run()? Now, each time I run the program it immediately prints "XI am the second thread.Y" without any delay, whatsoever! Where has the effect of wait() gone?
You have actually run into exactly why you should NEVER call
wait
ornotify(All)
on Thread (see the JavaDocs for Thread). Internally, Thread uses wait and notifyAll to implement Thread.join(), so what's happening in the second case is you thread enters wait, but then the other thread dies and calls notifyAll(), which wakes up your main thread.Use
Thread.sleep
if you just want to wait for an elapsed time, useThread.join
if you actually want to wait for the thread’s termination. Also, read the javadocs inObject
for proper usage ofwait
,notify
, andnotifyAll
.javaDoc:
The explanation about how the thread finishing sends a notifyAll is relevant and correct, +1 from me. I'll try to add some information about why this is relevant.
When you call
in the main thread, it is the main thread that does the waiting.
t
is the monitor that the main thread is waiting on. Your expectation that this should make yourt
thread go dormant is mistaken.The monitor here (the shared object being locked on, which happens to be
t
) is used to communicate between the different threads, a thread calls notifyAll on the monitor and the other threads waiting on the monitor receive the notification. You can think of the monitor as a shared communication point.In your first example, the thread t starts and finishes immediately (because it doesn't have anything to do). The thread finishes and sends its notification before the main thread starts waiting, so you see a delay until the wait times out.
In the second example, the thread t has something to print, there's a race condition between it and the main thread. It's a free-for-all, what happens first depends on accidents of timing. What you're seeing is that the thread
t
now has to print a line to the console, so it manages to keep busy long enough that it's still alive at the time the main thread starts to wait, allowing the main thread to receive the notification when t finishes, causing the main thread to cut its wait short.