Waiting for (or Joining) Threads to Die
In the previous example, we don’t have control over threads as we are unable to wait until a thread is done executing before going on with the rest of the program. The Thread class’s join() method waits until a thread is finished executing (also called waiting for a thread to die) before returning. Here is an example in which four new threads are created and they wait for each one to finish executing before ending in the main application. We can also check whether a thread is still alive or not using the isAlive() method. The following program (MultiThreading.java) demonstrates this concept.
MultiThreading.java
class CustomThread implements Runnable {
Thread t;
CustomThread(String name) {
t = new Thread(this, name);
System.out.println(t + " started.");
t.start();
}
@Override
public void run() {
try {
for (int i = 0; i < 5; i++) {
System.out.println(t + " is running..");
Thread.sleep(500);
}
}
catch (InterruptedException e) {
System.out.println(e);
}
System.out.println(t + " ended.");
}
}
public class MultiThreading {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + " started.");
CustomThread t1 = new CustomThread("1st");
CustomThread t2 = new CustomThread("2nd");
CustomThread t3 = new CustomThread("3rd");
CustomThread t4 = new CustomThread("4th");
System.out.println("Status of t1: " + t1.t.isAlive());
System.out.println("Status of t2: " + t2.t.isAlive());
System.out.println("Status of t3: " + t3.t.isAlive());
System.out.println("Status of t4: " + t4.t.isAlive());
try {
t1.t.join();
t2.t.join();
t3.t.join();
t4.t.join();
}
catch(InterruptedException e) {
System.out.println(e);
}
System.out.println("Status of t1: " + t1.t.isAlive());
System.out.println("Status of t2: " + t2.t.isAlive());
System.out.println("Status of t3: " + t3.t.isAlive());
System.out.println("Status of t4: " + t4.t.isAlive());
System.out.println(Thread.currentThread().getName() + " ended.");
}
}
Output:
The program shows the following output sequence during runtime.
main started.
Thread[1st,5,main] started.
Thread[2nd,5,main] started.
Thread[3rd,5,main] started.
Thread[1st,5,main] is running..
Thread[4th,5,main] started.
Thread[2nd,5,main] is running..
Status of t1: true
Status of t2: true
Status of t3: true
Status of t4: true
Thread[4th,5,main] is running..
Thread[3rd,5,main] is running..
Thread[4th,5,main] is running..
Thread[2nd,5,main] is running..
Thread[3rd,5,main] is running..
Thread[1st,5,main] is running..
Thread[3rd,5,main] is running..
Thread[1st,5,main] is running..
Thread[4th,5,main] is running..
Thread[2nd,5,main] is running..
Thread[1st,5,main] is running..
Thread[2nd,5,main] is running..
Thread[3rd,5,main] is running..
Thread[4th,5,main] is running..
Thread[4th,5,main] is running..
Thread[2nd,5,main] is running..
Thread[1st,5,main] is running..
Thread[3rd,5,main] is running..
Thread[3rd,5,main] ended.
Thread[1st,5,main] ended.
Thread[4th,5,main] ended.
Thread[2nd,5,main] ended.
Status of t1: false
Status of t2: false
Status of t3: false
Status of t4: false
main ended.
Explanation
In this example we have some control over threads as we are able to make the main thread wait for other threads to die. As it is evident from the program outcome, the main thread waits for these four threads to finish executing.
In fact, main will be the last thread to be ended; though the four other threads may have different output sequences among themselves. This is made possible by using the join() method of Thread class within the try..catch block.
Another point is that, if any thread object is alive, applying isAlive() method on it will return true; otherwise will return false.