Skip to content

Joining a Thread in Java

The join() method in Java is used to pause the execution of the current thread until the thread on which join() is called has completed its execution. This mechanism ensures that one thread waits for the completion of another before proceeding.

The join() method is part of the Thread class and provides a way to synchronize threads.


Syntax of join()

public final void join() throws InterruptedException

public final void join(long millis) throws InterruptedException

public final void join(long millis, int nanos) throws InterruptedException

Explanation of Parameters

  1. join(): Waits indefinitely for the thread to finish execution.
  2. join(long millis): Waits up to the specified number of milliseconds for the thread to finish.
  3. join(long millis, int nanos): Waits up to the specified number of milliseconds and nanoseconds for the thread to finish.

How join() Works

When a thread calls the join() method:

  1. The current thread goes into a waiting state.
  2. It resumes execution only after the target thread completes its execution or the specified timeout expires.

Example 1: Basic Usage of join()

class WorkerThread extends Thread {

    public void run() {

        for (int i = 1; i <= 5; i++) {

            System.out.println(Thread.currentThread().getName() + ” – Work ” + i);

            try {

                Thread.sleep(500); // Simulate some work

            } catch (InterruptedException e) {

                System.out.println(“Thread interrupted.”);

            }

        }

    }

}

public class ThreadJoinExample {

    public static void main(String[] args) {

        WorkerThread thread1 = new WorkerThread();

        WorkerThread thread2 = new WorkerThread();

        thread1.start();

        thread2.start();

        try {

            thread1.join(); // Main thread waits for thread1 to complete

            System.out.println(“Thread1 has finished.”);

            thread2.join(); // Main thread waits for thread2 to complete

            System.out.println(“Thread2 has finished.”);

        } catch (InterruptedException e) {

            System.out.println(“Main thread interrupted.”);

        }

        System.out.println(“Main thread execution completed.”);

    }

}

Output (example):

Thread-0 – Work 1

Thread-1 – Work 1

Thread-0 – Work 2

Thread-1 – Work 2

Thread1 has finished.

Thread2 has finished.

Main thread execution completed.

Explanation:

  • The main thread calls thread1.join() and waits until thread1 finishes its execution.
  • After thread1 completes, the main thread calls thread2.join() and waits for thread2.

Example 2: Using join(long millis)

class SlowThread extends Thread {

    public void run() {

        for (int i = 1; i <= 3; i++) {

            System.out.println(Thread.currentThread().getName() + ” – Step ” + i);

            try {

                Thread.sleep(1000); // Simulate work

            } catch (InterruptedException e) {

                System.out.println(“Thread interrupted.”);

            }

        }

    }

}

public class ThreadJoinWithTimeout {

    public static void main(String[] args) {

        SlowThread thread = new SlowThread();

        thread.start();

        try {

            thread.join(2000); // Wait for 2 seconds for thread to complete

        } catch (InterruptedException e) {

            System.out.println(“Main thread interrupted.”);

        }

        System.out.println(“Main thread continues after timeout or thread completion.”);

    }

}

Output (example):

Thread-0 – Step 1

Thread-0 – Step 2

Main thread continues after timeout or thread completion.

Thread-0 – Step 3

Explanation:

  • The main thread waits for 2 seconds using thread.join(2000).
  • If the thread does not complete within the specified time, the main thread resumes execution.

Key Points About join()

  1. Blocking Behavior:
    1. The join() method blocks the calling thread until the target thread finishes execution or the timeout expires.
  2. InterruptedException:
    1. If the current thread is interrupted while waiting, an InterruptedException is thrown.
  3. Ensures Sequential Execution:
    1. join() is useful when thread synchronization is needed to execute tasks in a specific order.
  4. Timeout Variants:
    1. The timeout versions (join(long millis) and join(long millis, int nanos)) are useful when you want to wait for a thread only for a limited period.
  5. Used in Multithreading Applications:
    1. join() is often used in applications where thread cooperation or synchronization is essential.

Example 3: Multiple Threads with join()

class TaskThread extends Thread {

    public TaskThread(String name) {

        super(name);

    }

    public void run() {

        for (int i = 1; i <= 3; i++) {

            System.out.println(Thread.currentThread().getName() + ” is working on step ” + i);

            try {

                Thread.sleep(500);

            } catch (InterruptedException e) {

                System.out.println(“Thread interrupted.”);

            }

        }

    }

}

public class MultipleThreadJoin {

    public static void main(String[] args) {

        TaskThread t1 = new TaskThread(“Thread-1”);

        TaskThread t2 = new TaskThread(“Thread-2”);

        TaskThread t3 = new TaskThread(“Thread-3”);

        t1.start();

        t2.start();

        t3.start();

        try {

            t1.join();

            t2.join();

            t3.join();

        } catch (InterruptedException e) {

            System.out.println(“Main thread interrupted.”);

        }

        System.out.println(“All threads have finished. Main thread ends.”);

    }

}

Output (example):

Thread-1 is working on step 1

Thread-2 is working on step 1

Thread-3 is working on step 1

All threads have finished. Main thread ends.


When to Use join()

  1. Ensuring Task Completion:
    1. Use join() when one thread depends on the result or completion of another.
  2. Sequential Execution:
    1. In cases where threads need to complete in a specific order.
  3. Coordination Between Threads:
    1. To manage dependencies or ensure proper synchronization between threads.

Conclusion

The join() method is a powerful tool in multithreaded programming for synchronizing threads. It allows threads to wait for the completion of others, enabling sequential execution and better coordination. Understanding its use and variants is crucial for effective thread management in Java.