How do I use Thread's join method?
Author: Deron Eriksson
Description: This Java tutorial shows how to use a Thread object's join method.
Tutorial created using: Windows Vista || JDK 1.6.0_11 || Eclipse JEE Ganymede SR1 (Eclipse 3.4.1)


The join() method of a Thread instance can be used to "join" the start of a thread's execution to the end of another thread's execution so that a thread will not start running until another thread has ended. If join() is called on a Thread instance, the currently running thread will block until the Thread instance has finished executing.

We can illustrate this with an example. The RunnableJob class implements Runnable. Its run() method displays the current thread's name and the time at which the run() method is executed. It then sleeps for 1 second.

RunnableJob.java

package com.cakes;

import java.util.Date;

public class RunnableJob implements Runnable {

	@Override
	public void run() {
		Thread thread = Thread.currentThread();
		System.out.println("RunnableJob is being run by " + thread.getName() + " at " + new Date());
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

The ThreadExample class creates a RunnableJob object. It creates 4 threads named "T1", "T2", "T3", and "T4" with the RunnableJob object. It calls start() and then join() on each thread, in order. This blocks the execution of the current (main) thread from proceeding until the thread has completed. This means that the main thread will block for 1 second at each join(), since the RunnableJob sleeps for 1 second. Following this, ThreadExample creates 4 more threads, "T5", "T6", "T7", and "T8". This time, no joins are called on these threads, so the main thread will not block.

ThreadExample.java

package com.cakes;

public class ThreadExample {

	public static void main(String[] args) throws InterruptedException {

		RunnableJob runnableJob = new RunnableJob();

		Thread thread1 = new Thread(runnableJob, "T1");
		Thread thread2 = new Thread(runnableJob, "T2");
		Thread thread3 = new Thread(runnableJob, "T3");
		Thread thread4 = new Thread(runnableJob, "T4");

		thread1.start();
		thread1.join();
		thread2.start();
		thread2.join();
		thread3.start();
		thread3.join();
		thread4.start();
		thread4.join();

		Thread thread5 = new Thread(runnableJob, "T5");
		Thread thread6 = new Thread(runnableJob, "T6");
		Thread thread7 = new Thread(runnableJob, "T7");
		Thread thread8 = new Thread(runnableJob, "T8");

		thread5.start();
		thread6.start();
		thread7.start();
		thread8.start();

	}

}

The console output of the execution of ThreadExample is shown here. Notice from the times displayed that we indeed see that T1, T2, T3, and T4 are all separated by 1 second delays. Also, notice that there are no delays for T5, T6, T7, and T8. Also, notice that T7 executes RunnableJob's run() method before T6. This occurred since there is no guarantee as to the order that T5, T6, T7, and T8 will execute the job code.

Console Output

RunnableJob is being run by T1 at Tue May 19 01:56:11 PDT 2009
RunnableJob is being run by T2 at Tue May 19 01:56:12 PDT 2009
RunnableJob is being run by T3 at Tue May 19 01:56:13 PDT 2009
RunnableJob is being run by T4 at Tue May 19 01:56:14 PDT 2009
RunnableJob is being run by T5 at Tue May 19 01:56:15 PDT 2009
RunnableJob is being run by T7 at Tue May 19 01:56:15 PDT 2009
RunnableJob is being run by T6 at Tue May 19 01:56:15 PDT 2009
RunnableJob is being run by T8 at Tue May 19 01:56:15 PDT 2009

Note that join() can also take times in milliseconds and nanoseconds as parameters. These values specify the maximum amount of time to wait before returning the blocked thread's state to RUNNABLE.