Java Threads
Overview
A thread in Java is the direction or path taken by the program for its execution. Thread in Java helps us to achieve multiprogramming where a program or process can operate more efficiently by executing more than one instruction at a time.
A thread in Java also helps a complicated or larger task to operate in the background without interrupting the main program. The Thread class and Runnable interface in Java help us to create and control a thread in Java.
Lifecycle of a Thread in Java
Let us now learn the overall life cycle (the process of thread creation to its termination) of a thread in Java.
A thread in Java goes through five states in the span of its creation to its termination:
- New State
- Active State
- Waiting/Blocked State
- Timed Waiting State
- Terminated State
1. New State
As the name suggests, the new state resembles the state when a thread in Java is just created.
2. Active State
A thread moves from the new state to the active state when the thread invokes the start() method. The thread in the active state can be in a runnable state or a running state.
- Runnable state: After the creation of thread in Java, when the thread is ready to run, it is moved from the new state to the runnable state. During the runnable state, the thread may be running or may be ready to run at any given instant of time. In the runnable state, there is a queue where the threads lie.
- Running state: A thread is moved from the runnable state to the running state by the thread scheduler for its execution. By the running state, we mean that the thread gets the CPU for its execution. Always a fixed duration of execution time is allocated to a thread in Java.
3. Waiting or Blocked State
Whenever a thread in Java goes to an inactive state for some time (period i.e. not permanently), then we say that the thread is present in the waiting or blocked state. Whenever the main thread calls the join() method (to attach itself with other thread(s)), then the main method or main thread goes into the waiting state. After invoking the join() method, the main thread waits for its child thread to be executed first.
When the child thread completed its execution, it sends a signal back to the main thread. after getting the completion signal for the child thread, the main thread is moved from the waiting state to the active state.
Note: Sometimes when a thread is working on data that is being used by some other thread then the current thread waits to acquire a lock on the shared data. This state is referred to as the blocking state.
4. Timed Waiting State
As we have discussed in the previous state when a process is waiting, and it continues to wait for a longer duration then the process is said to be in the timed waiting state. A thread can also move in the timed waiting state if the thread invokes a method with the time-out parameter. The thread exits the timed waiting state when the timeout is completed or the waiting resources are gained.
5. Terminated State
When the thread completes its instruction cycle (completes execution), the thread goes into the termination state. A thread may also go into the termination state due to some error. When the thread is not handled correctly or when some other execution(s) is raised by the thread then the thread is terminated as abnormal termination.
When we start the JVM or the Java Virtual Machine, a single thread (typically called the main method) is started. This main thread continues and executed other threads until the following conditions are met:
1. The exit() method has been called up.
2. All the other threads have exited after executing their instructions.
Note:
- The allocation of time of execution to a thread is governed by a thread scheduler.
- A thread in Java is executed as per the priority. The thread with higher priority is executed first then the threads with lower priorities are executed.
Refer to the image shown below to understand the flow of execution of a thread in Java.
How to Create a Thread in Java?
As we now know the entire lifecycle of a thread in Java, let us know how threads are created in Java. We have seen that there are two methods of creating a thread in Java.
- Extending Thread Class
- Implementing a Runnable interface
1. By Extending Thread Class
We declare a sub-class or a child class that inherits the Thread class. The child class should override the run() method of the Thread class. After the sub-class has overridden the run() method, the new thread can be associated with the main thread by invoking the start() method.
After invoking the start() method, the new thread can start its execution. When the new thread starts its execution, the main thread is moved to the waiting state.
Example:
Output:
2. By Implementing a Runnable Interface
We can also create a thread in Java by implementing the Runnable interface.
We pass the reference of the Runnable implemented class to the Thread object's constructor to create a new thread. After passing the reference, we invoke the start() method to start the execution of the newly created thread.
Example:
Output:
Running Threads
As we now know how to create a thread in Java. Let us code an example with more than one thread in a program. We can use the Runnable interface or Thread class method to implement the example.
Using the Thread Class Method for the Implementation
Output:
Using the Runnable Interface Implementation Method
Example:
Output:
Note: We can get different outputs of the above two implementations as threads can be executed in different manners. The execution is governed by the thread scheduler and associated priority.
Methods of Thread Class
Let us now know some of the most commonly used methods of the Thread class.
Method Name | Usage |
---|---|
public void run() | used to act as a thread. |
public void start() | used to start execution for a thread. |
public void sleep(long milliseconds) | used to temporarily terminate the invoking thread's execution for a specified duration of time. |
public void join() | used to wait for a thread to die. |
public void join(long milliseconds) | used to wait for a thread to die for a specified duration of time. |
public int getPriority() | used to get the priority of the thread. |
public int setPriority(int priority) | used to set or change the priority of the thread. |
public String getName() | used to get the name of the thread. |
public void setName(String name) | used to set or change the name of the thread. |
public Thread currentThread() | used to get the reference of currently executing thread. |
public int getId() | used to get the id of the thread. |
public Thread. State getState() | used to get the state of the thread. |
public boolean isAlive() | used to check if the thread is alive or not. |
public void yield() | used to temporarily pause the currently executing thread and allow other threads to execute. |
public void stop() | used to check if the thread is a daemon thread. |
public boolean isDaemon() | used to mark the thread as daemon thread. |
public void setDaemon(boolean b) | used to mark the thread as daemon or user thread. |
public void interrupt() | used to make interrupts to the thread. |
public boolean isInterrupted() | used to check if the current thread has been interrupted or not. |
public static boolean interrupted() | used to check if the current thread has been interrupted or not. |
Note: We have two more methods of the Thread class but they are now deprecated.
- public void suspend(): which is used to suspend the current thread.
- public void resume(): which is used to resume the currently suspended thread.
Constructors of Thread Class
In java.lang.Thread class, several constructors have been declared for different purposes. Some of them are:
- Thread(): no-argument constructor.
- Thread (String name): takes a string as an argument.
- Thread(Runnable r): takes reference (r) of a Runnable object as an argument.
- Thread(*Runnable r, String r): takes reference (r) of a Runnable object as well as a string as arguments.
Example to Create Java Thread Using the Thread Class: Thread(String Name)
We can use a different constructor of the Thread class i.e. Thread(String Name) to spawn or create new threads. Let us code an example to understand the working better.
Output:
Example to Create Java Thread Using the Thread Class: Thread(Runnable r, String name)
We can also use a different constructor of the Thread class i.e. Thread(Runnable r, String Name) to spawn or create new threads. The constructor takes reference (r) of a Runnable object as well as a string as arguments. Let us code an example to understand the working better.
Output:
Conclusion
- Thread in Java helps us to achieve multiprogramming where a program or process can operate more efficiently by executing more than one instruction at a time.
- A thread in Java also helps a complicated or larger task to operate in the background without interrupting the main program.
- The Thread class and Runnable interface in Java help us to create and control a thread in Java.
- A thread in Java goes through five states in the span of its creation to its termination namely- new state, active state, waiting or blocked state, timed waiting for the state, and terminated state.
- We declare a sub-class or a child class that inherits the Thread class. The child class should override the run() method of the Thread class.
- We can also create a thread in Java by implementing the Runnable interface. We pass the reference of the Runnable implemented class to the Thread object's constructor to create a new thread.
- In java.lang.Thread class, several constructors and methods have been declared for different purposes.