threads

Java Thread Join Example

In this article, I am going to show you an example of Thread.join. It can be used in a scenario where the calling thread has to rely on the results of execution of one or more sub-tasks and can’t proceed unless the threads executing these sub-tasks are done with their job.

In brief, Thread.join() provides you with wait & notification mechanism where the execution of the calling thread is suspended until the object called finishes its execution.

Before we start with the examples, let’s first go through the mechanics of Thread.join.

1. Thread.Join Flow

When Thread.join is called, it suspends the execution of the calling thread until the target thread is alive. Once the target thread is done with its job and terminates, the caller thread will automatically wake up.

In the below diagram, the caller thread starts two threads t1 and t2, each thread is assigned one specific task. The caller thread then calls on t1.join so that it is blocked from further execution till t1 finishes its job. Once t1 is done with its execution and terminates, it wakes up the caller thread. Next, caller thread calls t2.join to wait on t2 till it is done with its task. Once t2 finishes, caller thread wakes up and continues  in its execution.

Thread Join Flow
Figure 1: Thread Join Flow

 

Thread.join throws InterruptedException, if any thread has interrupted the current thread so when we call it we must make sure it is caught and dealt appropriately.

2. Thread.join variations

There are couple of variations on join() method:

  1. join (long milliseconds)
  2. join (long milliseconds, long nanos)

In the first version of the join() method, instead of waiting indefinitely for the thread called to terminate, the calling thread waits for the milliseconds specified as a parameter of the method.
The second version of the join() method is very similar to the first version, it receives the waiting period in number of milliseconds and the number of nanoseconds.

3. Example of Thread.join()

In this example, the main thread creates two threads and assigns each one a task. It then calls on join to wait for the thread’s completion. The first task calculates the average of numbers and the second task calculates the median. Once both tasks are done, the main thread prints the results.

ThreadJoinExample:

package com.javacodegeeks.threads;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class ThreadJoinExample {

	public static void main(String[] args) {
		Integer[] values = new Integer[] { 3, 1, 14, 3, 4, 5, 6, 7, 8, 9, 11,
				3, 2, 1 };
		Average avg = new Average(values);
		Median median = new Median(values);
		Thread t1 = new Thread(avg, "t1");
		Thread t2 = new Thread(median, "t2");
		System.out.println("Start the thread t1 to calculate average");
		t1.start();
		System.out.println("Start the thread t2 to calculate median");
		t2.start();
		try {
			System.out.println("Join on t1");
			t1.join();
			System.out
					.println("t1 has done with its job of calculating average");
		} catch (InterruptedException e) {
			System.out.println(t1.getName() + " interrupted");
		}
		try {
			System.out.println("Join on t2");
			t2.join();
			System.out
					.println("t2 has done with its job of calculating median");
		} catch (InterruptedException e) {
			System.out.println(t2.getName() + " interrupted");
		}
		System.out.println("Average: " + avg.getMean() + ", Median: "
				+ median.getMedian());
	}

	/**
	 * Calculate average of numbers. Sum all the int values and divide it by
	 * total count.
	 */
	private static class Average implements Runnable {
		private Integer[] values;
		private int mean;

		Average(Integer[] values) {
			this.values = values;
		}

		@Override
		public void run() {
			mean = 0;
			int n = values.length;
			for (int i : values) {
				mean += i;
			}
			mean /= n;
		}

		public int getMean() {
			return mean;
		}
	}

	/**
	 * Sorts the given int list and calculates the median value. If size is
	 * even, the mean of middle and middle-1.
	 *
	 */
	private static class Median implements Runnable {
		private Integer[] values;
		private int median;

		Median(Integer[] values) {
			this.values = values;
		}

		@Override
		public void run() {
			List sortedList = Arrays.asList(values);
			Collections.sort(sortedList);
			int n = values.length;
			int middle = n / 2;
			if (n % 2 == 0) {
				median = (sortedList.get(middle) + sortedList.get(middle - 1)) / 2;
			} else {
				median = sortedList.get(middle);
			}
		}

		public int getMedian() {
			return median;
		}

	}
}

Output:

Start the thread t1 to calculate average
Start the thread t2 to calculate median
Join on t1
t1 has done with its job of calculating average
Join on t2
t2 has done with its job of calculating median
Average: 5, Median: 4

4. Example of Thread.join(millis)

In this example, I will show the other variation of Thread.join which takes the waiting period as the parameter. The calling thread will wait only for the number of milliseconds passed in.
The main thread creates a thread and assigns it a sub task. Just to make sure sub task takes a while to complete, I have called Thread.sleep(100000) so that it is blocked for 100000 millis. Once the thread is started, the main thread calls on t.join(100) so that it can wake up after 100 millis irrespective of whether the called thread has done its job or not. After waking up, it checks whether the called thread is still alive. If it is, then it simply interrupts the thread to end its execution.

ThreadJoinMillisExample:

package com.javacodegeeks.threads;

public class ThreadJoinMillisExample {
	public static void main(String[] args) {
		SubTask subTask = new SubTask();
		Thread t = new Thread(subTask);
		t.start();
		try {
			System.out
					.println("Join on subTask thread but only for 100 millis");
			t.join(100);
			System.out.println("Main thread came out of join");
		} catch (InterruptedException e) {
			System.out.println("Main thread Interrupted!");
		}
		if (t.isAlive()) {
			System.out.println("SubTask is still alive, interrupt it");
			t.interrupt();
		}
	}

	private static class SubTask implements Runnable {

		@Override
		public void run() {
			try {
				Thread.sleep(100000);
			} catch (InterruptedException e) {
				System.out.println("Subtask Interrupted!");
			}
		}
	}

}

Output:

Join on subTask thread but only for 100 millis
Main thread came out of join
SubTask is still alive, interrupt it
Subtask Interrupted!

5. Example of InterruptedException

In this example, I will show you how Thread.join can be interrupted by the thread on which the calling thread is waiting. The main thread creates a thread and assigns a sub task to it and then calls on t.join() to wait for the results. The sub task thread interrupts the main thread once it has the results the main thread is interested in. After interruption, the sub task continues further executing some more task. Meanwhile, the main thread wakes up due to interruption and obtains the result from sub task.

ThreadJoinInterruptionExample:

package com.javacodegeeks.threads;

public class ThreadJoinInterruptionExample {
	public static void main(String[] args) {
		ThreadJoinInterruptionExample caller = new ThreadJoinInterruptionExample();
		caller.startSubTask();
	}

	public void startSubTask() {
		System.out.println("Start subtask");
		SubTask subTask = new SubTask(Thread.currentThread());
		Thread t = new Thread(subTask);
		t.start();
		try {
			t.join();
		} catch (InterruptedException e) {
			System.out.println("Interrupted, lets check the result");
		}
		System.out.println("Got the result? " + (subTask.getResult() != null));
	}

	private class SubTask implements Runnable {
		private Thread callerThread;
		private Object result;

		SubTask(Thread callerThread) {
			this.callerThread = callerThread;
		}

		@Override
		public void run() {
			doTask();
			System.out
					.println("task done, interrupt the thread waiting on the result");
			callerThread.interrupt();
			doSomeMoreTask();
		}

		private void doTask() {
			System.out.println("do task");
			result = new Object();
		}

		private void doSomeMoreTask() {
			System.out.println("do some more task");
		}

		public Object getResult() {
			return result;
		}

	}
}

Output:

Start subtask
do task
task done, interrupt the thread waiting on the result
do some more task
Interrupted, lets check the result
Got the result? true

Download the Eclipse Project

In this article, I have shown you Java Thread Join Examples.

Download
You can download the source code here: threadjoin.zip

Ram Mokkapaty

Ram holds a master's degree in Machine Design from IT B.H.U. His expertise lies in test driven development and re-factoring. He is passionate about open source technologies and actively blogs on various java and open-source technologies like spring. He works as a principal Engineer in the logistics domain.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button