Java Multithreading concept and join() method

I came across the join() while learning about race condition and I will clear the doubts I was having. So let us take this small example

Thread t2 = new Thread(
             new Runnable() {
                 public void run () {
                     //do something
                 }
              }
);
Thread t1 = new Thread(
             new Runnable() {
                 public void run () {
                     //do something
                 }
              }
);
t2.start(); //Line 11
t1.start(); //Line 12
t2.join();  //Line 13
t1.join();  //Line 14
System.out.print("<Want to print something that was being modified by t2 and t1>")

My AIM
Three threads are running namely t1, t2 and the main thread. I want to print something after the t1 and t2 has finished. The printing operation is on my main thread therefore for the expected answer I need to let t1 and t2 finish and then print my output.

So t1.join() just makes the main thread wait, till the t1 thread completes before going to the next line in program.

Here is the definition as per GeeksforGeeks:

java.lang.Thread class provides the join() method which allows one thread to wait until another thread completes its execution.

Here is one question that might solve your doubt

Q-> Will t1 thread get the time slice to run by the thread scheduler, when the program is processing the t2.join() at Line 13?

ANS-> Yes it will be eligible to get the time slice to run as we have already made it eligible by running the line t1.start() at Line 11.
t2.join() only applies the condition when the JVM will go to next line, that is Line 14.
It might be also possible that t1 might get finished processing at Line 13.


I'm not able to understand the flow of execution of the program, And when ob1 is created then the constructor is called where t.start() is written but still run() method is not executed rather main() method continues execution. So why is this happening?

This depends on Thread Scheduler as main shares the same priority order. Calling start() doesn't mean run() will be called immediately, it depends on thread scheduler when it chooses to run your thread.

join() method is used to wait until the thread on which it is called does not terminates, but here in output we see alternate outputs of the thread why??

This is because of the Thread.sleep(1000) in your code. Remove that line and you will see ob1 finishes before ob2 which in turn finishes before ob3 (as expected with join()). Having said that it all depends on when ob1 ob2 and ob3 started. Calling sleep will pause thread execution for >= 1 second (in your code), giving scheduler a chance to call other threads waiting (same priority).


You must understand , threads scheduling is controlled by thread scheduler.So, you cannot guarantee the order of execution of threads under normal circumstances.

However, you can use join() to wait for a thread to complete its work.

For example, in your case

ob1.t.join();

This statement will not return until thread t has finished running.

Try this,

class Demo {
   Thread t = new Thread(
                 new Runnable() {
                     public void run () {
                         //do something
                     }
                  }
    );
    Thread t1 = new Thread(
                 new Runnable() {
                     public void run () {
                         //do something
                     }
                  }
    );
    t.start(); // Line 15
    t.join();  // Line 16
    t1.start();
}

In the above example, your main thread is executing. When it encounters line 15, thread t is available at thread scheduler. As soon as main thread comes to line 16, it will wait for thread t to finish.

NOTE that t.join did not do anything to thread t or to thread t1. It only affected the thread that called it (i.e., the main() thread).

Edited:

t.join(); needs to be inside the try block because it throws the InterruptedException exception, otherwise you will get an error at compile time. So, it should be:

try{
    t.join();
}catch(InterruptedException e){
    // ...
}

First of all, when you create ob1 then constructor is called and it starts execution. At that time t.start() also runs in separate thread. Remember when a new thread is created, it runs parallely to main thread. And thats why main start execution again with next statement.

And Join() statement is used to prevent the child thread from becoming orphan. Means if you did'nt call join() in your main class, then main thread will exit after its execution and child thread will be still there executing the statements. Join() will wait until all child thread complete its execution and then only main method will exit.

Go through this article, helps a lot.