Java Thread Join Example

In previous article, we have discussed how to create and start a thread in java. In this article, we will learn how to use join() method in multithreading. The join() method waits for a thread to die.

Thread join() Method Overview

The join() method waits for a thread to die. In other words, it causes the currently running threads to stop executing until the thread it joins with completes its task.
The java.lang.Thread class has three overloaded versions of join methods:
  1. void join() - Waits for this thread to die.
  2. void join(long millis) - Waits at most millis milliseconds for this thread to die.
  3. void join(long millis, int nanos) - Waits at most millis milliseconds plus nanos nanoseconds for this thread to die.

Thread join() Method Example

We will first create a Task which will calculate the sum of 1-5 numbers. In the main thread lets create 4 tasks:
final Task task1 = new Task(500l);
final Task task2 = new Task(1000l);
final Task task3 = new Task(2000l);
final Task task4 = new Task(50l);
Now, let's create 4 threads to run above 4 tasks:
final Thread thread1 = new Thread(task1); 
final Thread thread2 = new Thread(task2);
final Thread thread3 = new Thread(task3);
final Thread thread4 = new Thread(task4);
Assign name to each thread and start all the 4 threads:
thread1.setName("thread-1");
thread2.setName("thread-2");
thread3.setName("thread-3");
thread4.setName("thread-4");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
In this example, when the target thread finishes the sum, the caller thread (main) wakes up and calls the task.getSum() method which will certainly contain the total sum as the target thread has already finished its job.
The task4 has a small sleep time and therefore it finishes the sum before the others. Hence, the main thread calls the thread4.join() but immediately returns to its execution as the thread4 is finished.
/**
 * This class demonstrate the how join method works with an example. 
 * @author Ramesh Fadatare
 *
 */
public class ThreadJoinExample {
    public static void main(final String[] args) throws InterruptedException {
        System.out.println("Thread main started");
  
       final Task task1 = new Task(500l);
       final Task task2 = new Task(1000l);
       final Task task3 = new Task(2000l);
       final Task task4 = new Task(50l);
       final Thread thread1 = new Thread(task1); 
       final Thread thread2 = new Thread(task2);
       final Thread thread3 = new Thread(task3);
       final Thread thread4 = new Thread(task4); 
       thread1.setName("thread-1");
       thread2.setName("thread-2");
       thread3.setName("thread-3");
       thread4.setName("thread-4");
       thread1.start();
       thread2.start();
       thread3.start();
       thread4.start();
  
       System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread1.getName());
       thread1.join();
       System.out.println(thread1.getName() + " finished! Result: " + task1.getSum());
  
       System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread2.getName());
       thread2.join();
       System.out.println(thread2.getName() + " finished! Result: " + task2.getSum());
  
       System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread3.getName());
       thread3.join();
       System.out.println(thread3.getName() + " finished! Result: " + task3.getSum());
  
       // As thread-4 already finished (smaller sleep time), the join call only immediately
      // returns the control to the caller thread
       System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread4.getName());
       thread4.join();
       System.out.println(thread4.getName() + " finished! Result: " + task4.getSum());
  
       System.out.println("Thread main finished");
    }
}

class Task implements Runnable {
     private long sleep; 
     private int sum;
 
     public Task(final long sleep) {
         this.sleep = sleep;
     }
 
     @Override
         public void run() {
             for (int i = 1; i <= 5; i++) {
                 System.out.println("[" + Thread.currentThread().getName() + "] Adding " + i);
                 sum += i;
                 try {
                     Thread.sleep(sleep);
                 } catch (final InterruptedException e) {
                     e.printStackTrace();
                 }
             }
        }
 
       public int getSum() {
             return this.sum;
       }
}
Output:
Thread main started
[thread-1] Adding 1
[thread-2] Adding 1
[thread-3] Adding 1
[main] waiting for thread-1
[thread-4] Adding 1
[thread-4] Adding 2
[thread-4] Adding 3
[thread-4] Adding 4
[thread-4] Adding 5
[thread-1] Adding 2
[thread-1] Adding 3
[thread-2] Adding 2
[thread-1] Adding 4
[thread-1] Adding 5
[thread-3] Adding 2
[thread-2] Adding 3
thread-1 finished! Result: 15
[main] waiting for thread-2
[thread-2] Adding 4
[thread-2] Adding 5
[thread-3] Adding 3
thread-2 finished! Result: 15
[main] waiting for thread-3
[thread-3] Adding 4
[thread-3] Adding 5
thread-3 finished! Result: 15
[main] waiting for thread-4
thread-4 finished! Result: 15
Thread main finished
Note that the output, main() thread finished it's executions last. Try to understand the example via looking into an output.
Note that join() method throws an InterruptedException, if any thread has interrupted the current thread.

Reference

Comments