Joining Threads in Java

Last Updated : 16 Jan 2026

In Java multithreading, threads often depend on the results of other threads. Java provides a simple way to handle such dependencies using the join() method. The join() method allows one thread to pause its execution until another thread has completed.

In this chapter, you will understand what the join() method is, why it is used, and how its different overloaded forms work in Java.

What is join() Method in Java?

The join() method is provided by the java.lang.Thread class. It allows the current executing thread to wait until the thread on which join() is called finishes its execution.

In simple terms: One thread waits for another thread to complete before moving forward.

How join() Method Works?

  • Suppose th is a thread object that is currently executing.
  • When th.join() is called, the calling thread enters the waiting state. (Read More: Different Thread States)
  • The calling thread resumes execution only after th has completed its execution (reaches the dead state).

Why Use join() Method?

The join() method is mainly used when:

  • A task must complete before another task starts
  • Thread execution order matters
  • You want to avoid race conditions caused by parallel execution

Overloaded join() Methods

Java provides three overloaded versions of the join() method. These allow threads to wait either indefinitely or for a specific amount of time.

1. join()

When join() is invoked without parameters, the current thread stops execution and enters the waiting state. It remains there until the target thread completes its execution.

If the waiting thread is interrupted, an InterruptedException is thrown.

Syntax

It has the following syntax:

2. join(long mls)

This version of the join () method allows the current thread to wait for a specified time (in milliseconds). The waiting ends when:

  • The target thread finishes execution, or
  • The specified time period expires

Just like sleep(), the actual waiting time depends on the operating system, so exact timing is not guaranteed.

Syntax

It has the following syntax:

Here, millis represents time in milliseconds.

3. join(long mls, int nanos)

This version of join() method allows even more precise waiting by specifying:

  • Milliseconds
  • Nanoseconds (additional)

The current thread waits until:

  • The target thread completes, or
  • The total waiting time (millis + nanos) expires

Again, timing accuracy depends on the operating system.

Syntax:

It has the following syntax:

Here, millis is milliseconds and nanos is additional nanoseconds.

Example of Joining Threads

The following example demonstrates how the join() method is used to make the main thread wait until a child thread completes its execution.

Output:

The current thread name is: main
The current thread name is: Thread - 0
0
The current thread name is: Thread - 0
1
The current thread name is: main
The current thread name is: Thread - 1
0
The current thread name is: Thread - 1
1
The current thread name is: Thread - 2
0
The current thread name is: Thread - 2
1

Explanation:

The above program shows that the second thread th2 begins after the first thread th1 has ended, and the thread th3 starts its work after the second thread th2 has ended or died.

The join() Method and InterruptedException

As discussed earlier, when a thread waiting using the join() method is interrupted, Java throws an InterruptedException. This happens when another thread interrupts the currently waiting thread.

Example

The following example demonstrates using join() method with InterruptedException:

Output:

The exception has been caught. java.lang.InterruptedException

More Examples of the join() Method

Let us now see some additional examples to understand how join() affects thread execution order.

Example: join() Method without Time Limit

The following example demonstrates how the join() method without any time limit makes one thread wait until another thread completes its execution.

Output:

       1
       2
       3
       4
       5
       1
       1
       2
       2
       3
       3
       4
       4
       5
       5

Here, t1 completes its execution first. Only after t1 finishes do t2 and t3 start executing.

Example: join(long milliseconds) Method

The following example demonstrates how the join(long milliseconds) method allows a thread to wait for a specified time period.

Output:

	1
       2
       3
       1
       4
       1
       2
       5
       2
       3
       3
       4
       4
       5
       5

In this case, t1 is allowed to execute for 1500 milliseconds (approximately 3 iterations). After that time expires, t2 and t3 begin execution even though t1 has not yet finished.