3
votes

Consider the following code

public class ThreadTest1
{
private static final long startTime = System.currentTimeMillis();

    public static void main(String args[])
    {
        Thread ct = new Thread(new ChildThread());
        ThreadTest1.print("starting child threads in MAIN");
        ct.start();
        synchronized(ct)
        {
            try
            {

            ThreadTest1.print("about to start wait() in MAIN");
            ct.wait();
            ThreadTest1.print("after wait() in MAIN");
            }
            catch(Exception e)
            {
            ThreadTest1.print("Exception in MAIN");
            }
        }
    }

    public static void print(String s)
    {
    System.out.println("Millisecond : "+(System.currentTimeMillis()-ThreadTest1.startTime)+"\t: "+s);
    }
}

class ChildThread implements Runnable
{
    public void run()
    {
        synchronized(this)
        {

        try
        {
        ThreadTest1.print("before thread notifyAll in CHILD");
        notifyAll();
        ThreadTest1.print("notifyAll over, sleep starts in CHILD");
        Thread.sleep(10000);
        ThreadTest1.print("after thread sleep in CHILD");

        }
        catch(Exception e)
        {
        ThreadTest1.print("Exception in CHILD");
        }
        ThreadTest1.print("End of run method in CHILD");
        }
    }
}

The ouput follows :

Millisecond : 12        : starting child threads in MAIN
Millisecond : 13        : about to start wait() in MAIN
Millisecond : 13        : before thread notifyAll in CHILD
Millisecond : 13        : notifyAll over, sleep starts in CHILD
Millisecond : 10015     : after thread sleep in CHILD
Millisecond : 10015     : End of run method in CHILD
Millisecond : 10016     : after wait() in MAIN

notifyAll() gets called at the 13th millisecond. But control comes out of wait() only at 10016th millisecond.

From the code given above, it appears as if the wait() call doesn't get over immediately after the notify() call.

But all documentations including the Java API, specify that the method calling wait() should get the lock immediately after the notify() call.

If wait() will not get over when notify() is called, then the need for notify() becomes void since the method calling wait() will automatically get control when the run method of the new thread gets over even if notify() is not called.

Waiting for someone to throw some light, if I am committing a mistake here.

4
You aren't synchronizing on the same object. Main thread is on ct which is the Thread, while the ChildThread is synchronized on this which is the ChildThread. - Sotirios Delimanolis
Very interesting. By all rights the main thread should continue to wait forever since nothing ever calls notify on the object it's waiting for. I suspect (but haven't found any documentation) that when a thread ends it implicitly calls notifyAll() on its Thread object. The idea of synchronizing on the Thread object itself is a little weird. - Jim Garrison
what condition are you waiting on? wait for a condition in a loop. Also, synchronization meaningful in situations where you have multiple threads. - Nishant
Thanks for the replies. The complete solution has been posted by Guillaume below. The sleep needs to be put outside the synchronization block. Yes, i mistook the code by waiting on the Thread object and notifying from Runnable subclass object. Thank you for the solutions. - Arul Jose

4 Answers

3
votes

The problem is that you are notifying and waiting on different objects. You wait() on the Thread and in the run() method you are calling on this ... which is a ChildThread.


This is obscured by the fact that you've misnamed your ChildThread class. That name implies that it is a Thread subclass, but it is actually a Runnable subclass.

2
votes

With the suggestions of other answers, here is a working implementation. Note that I also moved the sleep outside of the synchronized block. As a rule, synchronized blocks should always be as short as possible ...

public class ThreadTest {

    private static final long startTime = System.currentTimeMillis();

    public static void main(String args[]) {
        Thread ct = new ChildThread();
        ThreadTest.print("starting child threads in MAIN");
        ct.start();
        try {
            ThreadTest.print("about to start wait() in MAIN");
            synchronized (ct) {
                ct.wait();
            }
            ThreadTest.print("after wait() in MAIN");
        } catch (Exception e) {
            ThreadTest.print("Exception in MAIN");
        }
    }

    public static void print(String s) {
        System.out.println("Millisecond : " + (System.currentTimeMillis() - ThreadTest.startTime) + "\t: " + s);
    }

    private static final class ChildThread extends Thread {
        public void run() {
            try {
                ThreadTest.print("before thread notifyAll in CHILD");
                synchronized (this) {
                    notifyAll();
                }
                ThreadTest.print("notifyAll over, sleep starts in CHILD");
                Thread.sleep(1000);
                ThreadTest.print("after thread sleep in CHILD");

            } catch (Exception e) {
                ThreadTest.print("Exception in CHILD");
            }
            ThreadTest.print("End of run method in CHILD");
        }
    }
}
0
votes

2 problems here:

  1. wait and notify called on same objects and inside synchronized blocks which are synchronized on same objects. Yours are different. One is on a thead named ct and another is on a Runnable of type ChildThread.

  2. you are calling start before you wait. It is very much possible that notify is called before the main thread begins to wait. So you may miss the notify. After fixing point 1 try to adjust the code so that you minimize the wait and notify gap.

0
votes

As others have noted, the two threads are synchronizing on different objects. So the question becomes how to explain the 10-second delay in the main method.

Notice that if you change ChildThread to remove the synchronized block and notifyAll(), you get the same behavior.

class ChildThread implements Runnable
{
    public void run()
    {
        System.out.println(this);
//        synchronized (this)
//        {
            try
            {
//                MiscTest.print("before thread notifyAll in CHILD");
//                notifyAll();
//                MiscTest.print("notifyAll over, sleep starts in CHILD");
                Thread.sleep(5000);
                MiscTest.print("after thread sleep in CHILD");

            }
            catch (Exception e)
            {
                MiscTest.print("Exception in CHILD");
            }
            MiscTest.print("End of run method in CHILD");
//        }
    }

This indicates that, when a Thread ends, it does an implicit notifyAll() on its own Thread object, and any other threads waiting specifically on the Thread object are allowed to proceed. I was unable to find any documentation stating this, but clearly that is what is happening.