Every task or operation performed by OS is done using the Threads. A single program may have one or more Threads as per requirements. These Threads allow users to achieve parallelism and perform tasks more quickly without the chance of losing the data. Most of the time some tasks are dependent on the result which needs to be provided by another Thread. In these case scenarios, one should wait till the completion of a dependent Thread and this waiting process is mainly done via the “Thread.join()” method.

This guide covers the implementation and working of a Thread.join() method.

Java Thread.join() Method With Examples

The “join()” method of a “java.lang.Thread” class passes the execution of all upcoming Threads until the targeted Thread execution gets completed. The user can also pass time as an argument which makes the targeted Thread wait until the time has elapsed but if the thread gets executed before the elapsing time, then the Thread will no longer wait. 

Similarly, if the time of elapsing arrives but the Thread is not executed completely, then the execution will be stopped without considering the completion of the Thread. The “Thread.join()” method offers three overloaded functions that are mentioned below along with their syntax and basic examples.

Overloader 1: The “join()” Function 

It is the basic function that does not accept any value as an argument. It halts the execution of preceding Threads till the full execution of a targeted Thread. Its syntax appears like this:

public final void join()

Example

In this example, the “join()” is applied over the targeted threat and the preceding threads execute after its full execution:

public class Threadjoin extends Thread{
public void run(){
  for(int k=0;k<4;k++){
  try{
    Thread.sleep(500);
  }
  catch(Exception excep)
  {
    System.out.println(excep);
  }
  System.out.println(k);
  }
}
  public static void main(String args[]){

 //Generate Three Threads for demonstration purposes.
  Threadjoin thread1 = new Threadjoin();
  Threadjoin thread2 = new Threadjoin();
  Threadjoin thread3 = new Threadjoin();
//Start the execution of First Thread
  thread1.start();
  try{
  thread1.join();
  }
  catch(Exception e){
  System.out.println(e);
  }
  thread2.start();
  thread3.start();
}     
}

The working of the above code is as follows:

  • First, define a Thread “Threadjoin” that displays values from (0 – 3) after every “500” milliseconds using the “sleep()” method.
  • Next, create three instances of the “Threadjoin” Thread and start the execution of the first thread using the “start()” method. Then, apply the “join()” method over the started Thread to halt the remaining Thread until its execution.
  • In the end, call the “start()” method to start the execution of remaining Threads instances.

Output

The output confirms that other Threads are executed parallelly after the full execution of a first joined Thread:

Overloader 2: The “join( long millis )” Function 

This contains time in milliseconds as an argument after which the preceding Threads execution gets started. It may not wait exactly as long as you specify because it also depends on the OS for timing. Moreover, if the Thread execution is completed before the provided time then the preceding Threads gets executed without any waiting.

Its syntax is shown below:

public final synchronized void join(long millis)

Example

The below code is the same as described in the above section only the “1000” milliseconds are passed into the “join()” method:

public class Threadjoin extends Thread{
public void run(){
  for(int k=0;k<4;k++){
  try{
    Thread.sleep(500);
  }
  catch(Exception excep)
  {
    System.out.println(excep);
  }
  System.out.println(k);
  }
}
  public static void main(String args[]){ //Generate Three Threads for demonstration purposes.
  Threadjoin thread1 = new Threadjoin();
  Threadjoin thread2 = new Threadjoin();
  Threadjoin thread3 = new Threadjoin();
//Start the execution of First Thread
  thread1.start();
  try{
  thread1.join(1000);
  }
  catch(Exception excep){
  System.out.println(excep);
  }
  thread2.start();
  thread3.start();
}
}

The output of the above code confirms that the first Thread is partially executed within the time frame of “1000” milliseconds. After that time frame, other Threads are executed along with the remaining part of the already partially executed Thread:

Overloader 3: The “join( long millis, int nanos )” Function 

This function is similar to the one described in the above section. It just takes the extra mile and allows users to pass the nanoseconds as well as the milliseconds. The overall time frame for the targeted Thread execution time will be the addition of both provided values. Its syntax is:

public final synchronized void join(long millis, int nanos)

That’s all about the working of a Thread.join() method in Java.

Exception

Two types of exceptions are mostly raised during the utilization of a “Thread.join()” method which are stated below:

  • The “IllegalArgumentException” is raised when a user enters the milli or nanoseconds value in negative. Also, the stated exception occurs if the user’s value of nanoseconds exceeds the “999999” value after extending the value converts into milliseconds.
  • The “InterruptedException” occurs whenever a Thread tries to interrupt the current Thread which is in a waiting or running state. This interruption is performed by invoking the “interrupt()” method:

That’s all about the Thread.join() method in Java.

Conclusion

The “Thread.join()” method halts the preceding Threads for a specified time interval or till the complete execution of a targeted Thread. Once the time has elapsed or the execution is completed, the preceding Threads get executed. It generates a couple of exceptions when a user tries to enter negative values or when the currently working Thread gets interrupted. The deadlock state also occurs when two Threads invoke the “join()” method on each other. This guide has illustrated the working of a “Thread.join()” method in Java.