Skip to content

Java Thread Join Example

Ramesh Fadatare edited this page Sep 1, 2018 · 1 revision

In this article, we will learn how to use and different version of join() methods in thread management. 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.

Three overloaded versions of join methods are provided

  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(maintained in for loop). 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 names to each 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 output.

join() method throws an InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.