1

I found below code for replicating the join() behavior in Java. There are two possible execution path:

  1. When Main thread continues execution and enters into the synchronized block. It then has to wait for thread t to finish.
  2. When Thread t starts first and calls the run method, then Main thread waits to acquire the lock.

In both the scenarios there is no notify() but still program completes with appropriate output. Can you please let me know why Main thread is not waiting forever as there is no notify()?

public class SequentialTreadWithoutJoin {
     public static void main(String[] args) {
            MyThread t = new MyThread("myThread");
            t.start();

            synchronized(t){
                try {
                    System.out.println("Before wait");
                    t.wait();
                    System.out.println("After wait");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            for(int i = 0; i < 10; i++)
                System.out.println("Thread " + Thread.currentThread().getName() + " will continue after join and print : " + i );
        }
}


class MyThread extends Thread{
    public MyThread(String name) {
        super(name);
    }
    public synchronized void run(){
        System.out.println("Thread " + this.getName() + " will run for 1 minute");
        try {
            this.sleep(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Atul
  • 1,694
  • 4
  • 21
  • 30
  • Since this is about the way Java's thread wait works in particular, it belongs on Stack Overflow. – Gort the Robot Mar 07 '15 at 20:34
  • 2
    Java threads use wait and notify for internal purposes as well. It isn't safe to wait on them yourself. I believe this is mentioned in the Javadoc. – user207421 Mar 08 '15 at 03:39
  • 1
    If you change the lock object this won't happen. It looks like it has to do with thread termination. Since spurious wakeups are allowed, you have to guard against any reason (including none whatsoever) instead of expecting a matching `notify` was called. – Ben Manes Mar 08 '15 at 10:45

3 Answers3

4

First a comment. This doesn't reproduce the behaviour of join(), if you add a sleep between Thread.start() and the synchronized block for a longer time than the other thread sleeps, the code hangs (while a join() wouldn't)...

The answer to your question is well hidden in the Javadocs of Thread.join()

As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.

I think that the call to this.notifyAll() that is mentioned in the Javadoc is native, as I cannot find it anywhere in the source code of Thread.

Augusto
  • 28,839
  • 5
  • 58
  • 88
  • Thanks for highlighting that it's not recommended to call wait, notify methods on thread itself. I will try to fix that but my question is if I just call a wait method on some object, would it wait forever if there is no noitfy? – Atul Mar 08 '15 at 13:36
  • Up-voted for highlighting that this.notifyAll() gets called when a thread terminates. – Atul Mar 08 '15 at 13:39
  • Yes, if you call wait on another object that is not the thread, it would wait forever. – ReneS Mar 08 '15 at 17:44
-1

Working of Synchronization block

Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.

Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.

When a thread releases an intrinsic lock, a happens-before relationship is established between that action and any subsequent acquistion of the same lock.

Locks In Synchronized Methods

When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.

Sandeep
  • 1,154
  • 10
  • 16
-1

If not mistaken, your main thread calls wait for thread t, but wait() can only be called from the thread itself. Nobody can call your wait(). So t.wait() is useless because it is not called by t itself but the main thread.

t.wait() should be t.join(). In that case, the main thread would wait for the thread t to finish. Additionally the entire synchronized block can go, because it is only one thread that goes there. t is never reaching that code because t only runs the code of MyThread.run().

So after t.start() a simple t.join() would delay the main thread until t finishes.

Update: As Augusto highlighted, this program relies on implicit behavior of the JDK to work correctly. Upvoted his answer.

ReneS
  • 3,535
  • 2
  • 26
  • 35
  • 1
    wait, notify and notifyAll methods can be called on any object including thereads – Atul Mar 08 '15 at 13:31
  • See this here as well: http://stackoverflow.com/questions/1036754/difference-between-wait-and-sleep – ReneS Mar 08 '15 at 17:11
  • Please consult the wait() and notify() Javadoc of the class Object. It highlights what prerequisites have to be fulfilled to make it work. – ReneS Mar 08 '15 at 17:25
  • Please 'consult' it yourself, and quote the part that backs up your claim that `t.wait()` can only be called within the thread `t.` It isn't there. – user207421 Mar 08 '15 at 22:36
  • I guess the misunderstanding in this code is that you do not call wait() of the thread, but wait() of the lock which is in this case the thread object. One might get the impression that you cause a wait() of the thread or a wait for the thread. You wait on the lock and by chance the dying thread calls a last notifyAll(). – ReneS Mar 09 '15 at 10:06
  • I guess the misunderstanding in this code is that you do not call wait() of the thread, but wait() of the lock which is in this case the thread object. One might get the impression that you cause a wait() of the thread. – ReneS Mar 09 '15 at 10:06