Skip to content

YourNote 801: Thread Join

Zhamri Che Ani edited this page Jun 22, 2026 · 1 revision

Java Thread Join

What is join()?

The join() method is used to make one thread wait until another thread finishes its execution.

In simple terms:

"Thread A calls join() on Thread B, so Thread A will pause and wait until Thread B completes."


Why Do We Need join()?

Without join(), multiple threads execute independently and the main thread may finish before worker threads complete.

join() ensures:

  • Proper execution order
  • Synchronization between threads
  • Main thread waits for worker threads
  • Results are available before continuing

Syntax

thread.join();

The current thread waits until thread terminates.


Simple Example

class MyThread extends Thread {
    public void run() {
        System.out.println("Worker Thread Started");

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Worker Thread Finished");
    }
}

public class Main {
    public static void main(String[] args) throws Exception {

        MyThread t1 = new MyThread();

        t1.start();

        t1.join();   // Wait for t1 to finish

        System.out.println("Main Thread Finished");
    }
}

Output

Worker Thread Started
Worker Thread Finished
Main Thread Finished

What Happens Without join()?

t1.start();

System.out.println("Main Thread Finished");

Possible output:

Main Thread Finished
Worker Thread Started
Worker Thread Finished

The main thread does not wait.


Multiple Threads with join()

class Task extends Thread {
    private String name;

    public Task(String name) {
        this.name = name;
    }

    public void run() {
        System.out.println(name + " started");

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {}

        System.out.println(name + " finished");
    }
}

public class Main {
    public static void main(String[] args) throws Exception {

        Task t1 = new Task("Thread-1");
        Task t2 = new Task("Thread-2");

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("All threads completed");
    }
}

Output

Thread-1 started
Thread-2 started
Thread-1 finished
Thread-2 finished
All threads completed

Join with Timeout

Sometimes we don't want to wait forever.

Syntax:

thread.join(milliseconds);

Example:

t1.join(2000);

Meaning:

Wait at most 2 seconds for t1.

After 2 seconds, the current thread continues whether t1 finishes or not.


Example of Join with Timeout

class MyThread extends Thread {
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {}

        System.out.println("Worker finished");
    }
}

public class Main {
    public static void main(String[] args) throws Exception {

        MyThread t1 = new MyThread();

        t1.start();

        t1.join(2000);

        System.out.println("Main continues");
    }
}

Possible Output

Main continues
Worker finished

Because main only waited 2 seconds.


How join() Works Internally

When a thread calls:

t1.join();

The JVM:

  1. Checks if t1 is still alive.
  2. If yes, the current thread enters WAITING state.
  3. When t1 finishes, JVM wakes up waiting threads.
  4. Current thread resumes execution.

Real-World Example: Download Files

Imagine downloading 3 files before creating a report.

download1.start();
download2.start();
download3.start();

download1.join();
download2.join();
download3.join();

generateReport();

Without join(), the report may be generated before downloads finish.


Real-World Example: Parallel Calculation

sumThread.start();
averageThread.start();

sumThread.join();
averageThread.join();

displayResult();

The result is displayed only after all calculations complete.


Join vs Sleep

Feature join() sleep()
Wait for another thread Yes No
Wait fixed time Optional Yes
Synchronization Yes No
Releases monitor lock No No
Throws InterruptedException Yes Yes

Example

t1.join();

Wait until thread finishes.

Thread.sleep(3000);

Wait exactly 3 seconds.


Common Mistake

Wrong

t1.join();
t1.start();

Output:

No waiting occurs

Reason:

join() is called before thread starts.

Correct

t1.start();
t1.join();

Common Use Cases

1. Waiting for Worker Threads

worker.start();
worker.join();

2. Waiting for Multiple Tasks

for(Thread t : threads) {
    t.join();
}

3. Parallel Processing

task1.start();
task2.start();
task3.start();

task1.join();
task2.join();
task3.join();

4. Fork-Join Style Processing

leftTask.start();
rightTask.start();

leftTask.join();
rightTask.join();

mergeResults();

Advantages of join()

  • Simple synchronization mechanism
  • Easy to understand
  • Prevents premature program termination
  • Ensures task completion before proceeding
  • Useful in parallel processing

Disadvantages of join()

  • Can block threads unnecessarily
  • May reduce concurrency
  • Not suitable for complex synchronization
  • Better alternatives exist for advanced applications:
    • ExecutorService
    • CompletableFuture
    • CountDownLatch
    • ForkJoinPool

Clone this wiki locally