Multithreading — thread life cycle, thread join(), daemon threads

Thread life cycle

- New
- Running
- Waiting — [Blocked, Waiting, TimedWaiting]
- Dead

New — when a thread is instantiated and ready to use. It is the state when we have not started the thread yet.
Running — a thread enters this state after we have started the thread. The thread is executing its task in this state
Waiting — a waiting state corresponds to three scenarios — Blocked, Waiting, TimedWaiting since a thread may enter this state in different scenarios. For example, a when a thread tries to acquire the lock, it enters a Blocking state; when a thread waits for execution of another thread, then the thread enters a Waiting state and when a thread waits only for a specified amount of time for execution of another thread, the thread enters a TimedWaiting state. A thread goes back to a running state as soon as other threads have executed or notified the current thread to continue. A thread may infinitely change its state from a running state to a waiting state and vice versa.
Dead — a thread enters this state when after full execution, i.e. finishing its task, or due to some exceptions. A thread after having executed cannot be started again. If we try to start a thread in a dead state, we will get a IllegalStateException.
We will speak about locks in the following posts.

Thread States

Thread join()

Another useful method that is provided by Thread classjoin().
While writing multithreaded programs, there may be cases when we would like to wait for some thread to finish its execution and after that continue the execution of another thread. In such cases — join() comes into play. The join() method allows one thread to wait for the completion of another.

Let’s consider the following examples:

In this example, we create a new thread — threadTwo, that sleeps for two seconds and counts till 1000. And then, it print the message that it has finished its execution. If we run this program, we will get the following output.


As soon as threadTwo starts executing, main() method continues its execution, it prints — “Main method executing” and finishes its execution. Simultaneously, threadTwo is executing, it counts till 1000, then it prints — “Counter thread has finished its execution, counter = 1000” and finishes its execution.

But what if we want the main thread wait for the execution of threadTwo? How can we achieve that? Pretty simple, using join() solves that.

The code snipped is nearly the same with the snipped above with a small difference. In line 17, right after threadTwo.start() we add method calling threadTwo.join(). If we run this program, we will get the following output.


The order of print statements has changed in this example. Right after starting threadTwo, mainThread calls join() method. This causes main thread to stop executing and wait for threadTwo to finish its execution. As we can see from the output, the threadTwo executes, it counts till 1000, prints the message — “Counter thread has finished its execution, counter = 1000” and finishes its execution. After that mainThread continues its execution and prints the following statement — “Main method executing”.

As for extra information, if there is an exception during threadTwo execution, the main thread continues its execution similar to when threadTwo executes successfully, there will not be deadlock situations.

Daemon Threads

Daemon threads function as helper threads, they execute and perform operations in the background. For example, garbage collection in Java runs as daemon thread.

In Main Thread, we can create as many threads necessary (child threads of the main thread). Moreover, Thread class provides a method — setDaemon(boolean) that enables a user thread turn into a daemon thread.

Daemon Threads:
— a low priority thread that run in the background
— a daemon thread are terminated by the JVM when all other worker thread finish execution.
— usually daemon threads are used for IO operations and services (in smartphones for Bluetooth or NFC communication)

The main difference between a user thread and a daemon thread is that when all the worker (=main or user thread) threads finish execution or die, daemon threads are terminated by the JVM automatically even if they are still executing.

A code snippet above shows prints the thread-name that starts the main() method. Thread.currentThread() — returns the currently running thread.


Let’s define our own daemon thread. We will create a daemon thread that will print a message every second.

In the code snippet above, we create two threads and name them as — worker and daemon. The thread — worker sleeps for three seconds, prints a message — “Thread is finishing its execution with name: Worker” and then it finishes execution.
The thread — daemon every second prints the message — “Thread is executing with name: Daemon” and never quits the loop. We set daemonFlag as true of the thread — daemon in line 25. It will run infinitely until the other threads are alive.
In lines 26, 27 we start our threads — worker and daemon. Main thread continues execution — prints the message “Thread is executing with name: main” and finishes execution.
As soon as the thread — worker finishes its execution, there will no worker threads left and the thread — daemon will be terminated by the JVM.
If we run the program the program, we will get the following output.


Additionally, setDaemon(boolean) can only be called if the thread is in a New state and has started yet, otherwise we will get IllegalThreadStateException.

In this series of post in Multithreading, we have discussed thread lifecycle, Thread.join() method and daemon threads. The more interesting is yet to come. Subscribe and stay tuned to be the first to read new posts.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store