To ensure that a thread (referenced by some reference say threadRef) is finished, then you join() on that reference. like threadRef.join() if that thread is finished, then join() returned immediately otherwise join() will blocked until that thread get finished. For example if you create three thread (a, b, c) for doing three different task A, B, C, from your main thread, but you need some initialization processing (which must be executed before start-up of a, b, c) and shutdown processing (which must be executed after finishing of a, b, c) then you may code like this // in main() System.out.println("System started"); initialization(); // a, b, c are not running yet. System.out.println("initialization complete "); Thread a = new Thread(new Task_A_RunnableClass()); Thread b = new Thread(new Task_B_RunnableClass()); Thread c = new Thread(new Task_C_RunnableClass()); a.start(); System.out.println("Thread "a" started "); b.start(); System.out.println("Thread "b" started "); c.start(); System.out.println("Thread "c" started "); //Now wait for all thread to finished. a.join(); System.out.println("Thread "a" finiished "); b.join(); System.out.println("Thread "b" finiished "); c.join(); System.out.println("Thread "c" finiished "); shutdown(); // a, b, c are finished now. System.out.println("System shutdown..... ");