Skip to content

JAVA Threads : Join() and wait() methods

September 7, 2007
tags:

We all know that there are a lot of things in JAVA and to all of us (or rather to all the people I met till date, feel that Threads are the most tricky to understand as far as their real time behavior is concerned). This topic is about the behavior of the join method and its comparison to the wait method. I am making this comparison because the join method calls the wait method internally.

Wait() : If a thread calls wait method on an object (obliviously that thread must already have acquired the lock of the object it is calling the wait method on, otherwise a runtime exception is thrown), that thread releases the object and goes to the waiting state. So in all the wait call forces the thread to release the object it is calling wait on.

Join() : If a thread (name it T1) calls the join method on another Thread (remember the wait method is in the Object class and the join method is specific to the Thread class and is present in the Thread class) named T2, then T1 waits for T2 to complete its execution before it continues from that point. Now think what will happen. Will thread T1 leave the locks on the object it has acquired lock on or not ? If we consider the fact that the join method internally calls the wait method the answer that pops up immediately is that “obviously it should leave the lock“, which is WRONG !!!!

For a moment lets assume this answer is correct. Now imagine the scenario, where the thread T1 has called this wait inside a synchronized lock where it has acquired a lock on a String object “abc” and has called the T2.join() inside this block. Now as this call has been made by T1 inside the synchronized block, it obviously means that it needs the lock on the “abc” object to continue the execution further. If T1 has released the lock on “abc” object it will be rescheduled by the thread scheduler to acquire lock on “abc”. But it is not guaranteed tha it will acquire the lock as soon as the thread T2 completes. So in this case some other thread T3 might acquire the lock on “abc” and enter the same synchronized block which the thread T1 already half way !!!! So if the join method makes the calling thread leave the locks, then whole whole use of the synchronized block is ruined.

Wait() inside Join() mystery : The wait method call in side the join method implementation is being called on “this” i.e the thread on which join was called (T2). That wait call does not have to do anything with the calling thread (T1). That means the join call does not causes the calling thread to release a lock on any object and it simply makes it wait till the thread it called join on completes its execution keeping all the locks it already acquired.

I tried the above theory with the following example code:

class AThread extends Thread
{

public void run()
{

System.out.println(“T2 started”);
synchronized (Test2.lock)

{

System.out.println(“Hi hello”);

}

}

}

public class Test implements Runnable
{

public static final String lock = “lock”;
public static final String lock1 = “lock1”;
static Test t = new Test();
static Thread T1 = new Thread(t, “Thread T1”);
static AThread T2 = new AThread();

public static void main(String[] args)
{

T1.start();
Thread.yield();
T2.start();

}

public void run()
{

synchronized (lock)

{

System.out.println(“T1 started”);
try
{

System.out.println(“waiting for T2 to join”);
T2.join();

}
catch (InterruptedException e)
{

System.out.println(“e.getMessage() = ” + e.getMessage());

}
System.out.println(“T1 ended”);

}

}

}

Running the above program produces the following output:

T1 started
T2 started
waiting for T2 to join

And the execution locks here as Thread T2 tries o acquire lock on the “lock” object which has already been acquired by thread T1 and as T1 has called join on T2, T1 does not leave the lock on the “lock” object and thus a deadlock occurs.

Note: The call to the yield() between the cal to the start() method of T1 and T2 is just to increase the possibility of starting the T1 thread and go a lil ahead on the execution line before the ThreadT2 is started. If the thread T2 starts first, then there would br no deadlock here as the lock will be gained by thread T1 and the execution will complete smoothly. Remember the above example is a 99% deadlock situation and so you should always avoid such situations.

Advertisements
22 Comments leave one →
  1. Tanmoy permalink
    December 31, 2008 9:54 am

    Hi Sanjeev,
    This blog is really helpfull and very interesting. After reading this I am eagerly waiting look for other blogs from you. Thnks for the nice blog. Hope to see more from you.

  2. May 25, 2009 5:40 am

    Thank you.. As you can see I am not a frequent blogger. I am trying to work on this try to be a little regular. You can probably see some of the Ruby and Rails stuff coming from my side in near future.

  3. Michael Wu permalink
    March 8, 2011 3:59 pm

    Hey, run your sample. Line get error, where is Test2?
    synchronized (Test2.lock)

  4. Michael Wu permalink
    March 8, 2011 4:20 pm

    Oh chnged to synchronized (Test.lock)

  5. Michael Wu permalink
    March 8, 2011 4:30 pm

    class AThread extends Thread
    {
    public void run()
    {
    System.out.println(“T2 started”);

    //synchronized (Test.lock) can see dead lock

    synchronized (Test.lock1) //then you can see t1 start first, wait t2 done,
    {
    System.out.println(“Hi hello: “);
    Thread.yield();

    }
    System.out.println(“Ahread ended “);
    }
    }

  6. KULDEEP VISHWAKRMA permalink
    March 8, 2011 4:52 pm

    DIFFRENCE B/W RUNNABLE INTERFACE AND THREAD CLASS
    Hi friends..
    We can implement multithreading concept in two way first one is Runnabe interface and second one is Thread Class both are provided by java but in the Runnable interface provide flexibility to extends any other class but in the Thread class we can’t extend any other class because java can’t provide facility of multiple inheritance………One thing is that Runnable interface internally work as Thread Class.**

    thanks.
    regards
    KULDEEP KUMAR VISHWAKARMA,

    • July 27, 2011 3:13 pm

      Wow really? Thanks for that incredibly true yet incredibly unrelated statement about multithreading in Java!

  7. rajesh permalink
    March 31, 2011 2:11 pm

    this blog is very useful

  8. Dan Manastireanu permalink
    April 20, 2011 3:57 pm

    Good article, I have just one remark:
    “the join call does not causes the calling thread to release a lock on _any_ object” is correct in almost all scenarios.
    The join method actually releases any locks the current thread has on the thread on which join is applied.(i.e. if the lock is actually made on the thread object we are joining)

    Consider this simple method: “synchronized void doWait(){ this.wait(); }”. This will make the calling thread release any lock it has on the object it was called on.(i.e. the object represented here by the “this” keyword)

    Here is a full running example. If join would not release any locks at all, than the following would result in a deadlock situation, but it doesn’t. If you replace the locking object with anything but the thread, than it will lock, as expected.

    final Thread t = new Thread() {
    @Override
    public void run() {
    System.out.println(“thread: waiting for lock”);
    synchronized (this) {
    System.out.println(“thread: has lock”);
    }
    };
    };
    System.out.println(“main: waiting for lock”);
    synchronized (t) {
    System.out.println(“main: has lock”);
    t.start();
    Thread.sleep(1000);
    System.out.println(“main: join thread”);
    t.join();
    System.out.println(“main: join complete”);
    }

    Output:
    main: waiting for lock
    main: has lock
    thread: waiting for lock
    main: join thread
    thread: has lock
    main: join complete

    Output(if another object is used as lock for both synchronized blocks):
    main: waiting for lock
    main: has lock
    thread: waiting for lock
    main: join thread
    … blocked …

  9. Ver Schlinger permalink
    June 24, 2011 8:13 am

    This rather looks like an reentrant lock. So no deadlock can occur.

  10. baba smith permalink
    November 1, 2011 6:01 pm

    I’m quite confused with that ‘join’ issue.

    From the example that shows the deadlock I learn that nothing is released when calling join(). And this is why there’s a deadlock.

    But I read in Java Puzzlers (chapter 9, puzzler 77 “TheLockMessMonster”: http://my.safaribooksonline.com/book/programming/java/032133678x/more-library-puzzlers/ch09lev1sec2) that:
    “Internally, Thread.join calls Object.wait on the Thread instance
    representing the thread being joined. This releases the lock for the duration
    of the wait.”.
    This argument is backed with an example.

    Since both arguments are shown with a working example, I’d say that calling join() does release some lock(s) but not all.

    Is that right? Can you explain which locks are release and which are not? Also, I see that in the Java Puzzlers example that call is “join();” and not “someThread.join();”. What does it mean?

    Thanks!

  11. November 25, 2011 6:57 am

    what is happens when two finally blocks are present in a class…..?

  12. Govardhan permalink
    January 13, 2012 1:57 pm

    given 2 ways to implement a thread can we extend thread class and implement runnable method simultaneously ?

  13. Govardhan permalink
    January 13, 2012 1:58 pm

    sorry. its runnable interface and not runnable method !

  14. Mahanth permalink
    March 10, 2012 1:27 pm

    Here there is a Bug in the code written by Sanjeev :

    when we start a thread the thread goes to the “thread Queue” and the thread scheduler will choose any thread and assigns to the cpu to start execution.There is no control on which thread is selected by the thread scheduler ” until and unless some priority is given ” . Here T1 and T2 threads are started they go the thread queue and ” how do you know that T1 will execute first ?” as there is no guarantee on which thread will be selected by the thread scheduler ( as per the java specification ) . lets say if T2 gets an opportunity to execute then inside run you have written T2.join() … so T2 will join itself leading to dead lock. Please change the code or put a checking condition to see whether the current thread is really T1.

    Thread.currentThread()— method

    public static void main(String[] args)
    {

    T1.start();
    Thread.yield();
    T2.start();

    }

    public void run()
    {

    synchronized (lock)

    {

    System.out.println(“T1 started”);
    try
    {

    System.out.println(“waiting for T2 to join”);
    T2.join();

    }
    catch (InterruptedException e)
    {

    System.out.println(“e.getMessage() = ” + e.getMessage());

    }
    System.out.println(“T1 ended”);

    }

  15. Jitendra permalink
    March 17, 2012 7:15 am

    Very valid point what Mahanth is suggesting , this code written on the top leads to deadlock.

  16. July 7, 2012 2:48 am

    Hi there would you mind stating which blog platform you’re using? I’m going to start my own blog soon but I’m having a tough time choosing between BlogEngine/Wordpress/B2evolution and Drupal. The reason I ask is because your design and style seems different then most blogs and I’m looking for something completely unique. P.S Sorry for being off-topic but I had to ask!

    • Sanjeev Mishra permalink*
      August 21, 2012 6:18 am

      I am using WordPress!!

  17. February 20, 2013 2:43 am

    Great article. by the way In order to join threads in Java, order is very important. Here is a good exercise to learn how to join threads in Java

  18. April 17, 2014 10:26 am

    I’m not that much of a internet reader to be honest but your
    blogs really nice, keep it up! I’ll go ahead and
    bookmark your website to come back in the future.
    Cheers

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: