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.

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.

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.

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.