In the previous tutorial, we have discussed about Multithreading in Java. In this tutorial, we will discuss in detail Thread in Java, how to create a java thread and thread lifecycle.
Table of Contents
Java Threads
A thread in Java is a lightweight process or the smallest unit of a process. Each thread performs a different task and hence a single process can have multiple threads to perform multiple tasks. Threads use shared resources and hence requires less memory and less resource usage. Threads are an important concept in multithreading. The main method itself is a thread that runs the Java program.
Java thread constructors
Below are the common constructors of the Java Thread class.
Constructor | Description |
---|---|
Thread() | Creates a new Thread object |
Thread(String name) | Creates a new thread with the specified name |
Thread(Runnable r) | Creates a new Thread object with the object that has run method that is invoked when it calls the start() method |
Thread(Runnable r, String name) | Creates a new Thread object with the specified name. r - object that invokes its run method when the thread starts execution |
Thread(ThreadGroup group, Runnable r, String name) | Creates a new thread object that specifies a thread name, run method object and belongs to the specified thread group |
Java thread methods
Below are the methods of the Thread class
Method | Description |
---|---|
void checkAccess() | Checks if the current thread has permissions to modify the thread |
ClassLoader getContextClassLoader() | Returns the context ClassLoader of the thread |
long getId() | Returns the id or identifier of the current thread which is a long value. |
String getName() | Returns the string name |
int getPriority() | Returns the priority of the thread |
State getState() | Returns the state of the thread |
ThreadGroup getThreadGroup() | Returns thr thread group to which the thread belongs to |
void interrupt() | Interrupts the thread |
boolean isAlive() | Checks if the thread is alive |
boolean isDaemon() | Checks if the thread is a daemon thread |
boolean isInterrupted() | Checks if the thread is interrupted |
void join() | Waits for the thread to die |
void join(long millis) | Waits for atmost specified milliseconds for the thread to die |
void run() | Calls the Runnable run method |
void setDaemon(boolean on) | Sets the thread as daemon thread or user thread |
void setName(String name) | Sets the thread's name |
void setPriority(int priority) | Sets the thread's priority |
void start() | Starts the thread execution |
int activeCount() | Returns the number of active threads |
Thread currentThread() | Returns the reference of the current executing thread |
void sleep(long millis) | Makes the thread temporarily sleep for the specified milliseconds |
boolean holdsLock(Object o) | Returns true if the thread holds a monitor lock |
Create a Java thread
We can create a new Java thread in 2 different ways as described below:
Thread class
We can create a new Thread object by extending the Thread class. To initiate the thread execution, we can use the start() method. Once it executes the start() methods, it automatically calls the run() method that we define while extending the Thread class. We generally create a thread using the Thread class when we want to implement only the Thread functionality
Example
The below example shows how to create a Java thread using the Thread class. Here we create 2 threads and invoke them using the start() method. When the thread executes the start() method, it automatically calls the run() method.
public class ThreadDemo extends Thread { public void run() { System.out.println("Thread " + Thread.currentThread().getId() + " running"); } public static void main(String[] args) { ThreadDemo t = new ThreadDemo(); ThreadDemo t1 = new ThreadDemo(); t.start(); t1.start(); } }
Thread 12 running Thread 13 running
Runnable interface
Another method to create a new thread is by implementing the Runnable interface. This interface has only 1 public run() method that we need to implement in the class that creates a thread. The run() method is executed automatically when we invoke the start() method using the thread object. We normally create a new thread by using the Runnable interface when we want to implement more functionalities other than the thread.
Example
This example shows how to create a Java thread by implementing the Runnable interface where we need to override the run() method.
public class ThreadRunnableDemo implements Runnable{ public static void main(String[] args) { ThreadRunnableDemo tr = new ThreadRunnableDemo(); Thread t = new Thread(tr); t.start(); } @Override public void run() { System.out.println("Thread " + Thread.currentThread().getId() + " running"); } }
Thread 12 running
Advantages of Java thread
- Threads share resource and hence results in less memory usage
- It is a light-weight process
- Context-switching is less expensive
- Inter-thread communication is easier
- Performs asynchronous processing
Thread lifecycle
A Java thread traverses through various stages where at each stage it performs different functionalities. The lifecycle of a thread starts when the thread calls the start() method.
- New: When we create a new thread, it is in a new state before we call the start() method.
- Runnable: A thread takes this state when it calls the start() method and waits for the scheduler to pick up the thread.
- Running: When the thread is in execution, it is in a running state.
- Waiting: Thread is in waiting state when it has to wait for other threads to complete execution as part of the synchronization process.
- Dead: When the thread is terminated, it is in the dead state
Naming a thread
We can provide a name to a thread in Java which helps us to distinguish between different threads that are executing. It is possible to pass the name as a string while creating a new thread either using the Thread class or a Runnable interface. To retrieve the thread name, we can use the method getName()
that belongs to the Thread class.
public class ThreadDemo extends Thread { public static void main(String[] args) { Thread t1 = new Thread("Thread 1") { public void run() { System.out.println("Thread " + Thread.currentThread().getId() + " running"); } }; Thread t2 = new Thread("Thread 2") { public void run() { System.out.println("Thread " + Thread.currentThread().getId() + " running"); } }; t1.start(); System.out.println("Thread name: " + t1.getName()); t2.start(); System.out.println("Thread name: " + t2.getName()); } }
Thread name: Thread 1 Thread 12 running Thread name: Thread 2 Thread 13 running
We can also pass the thread name while creating a thread using the Runnable interface as described below.
public class ThreadRunnableDemo implements Runnable{ public static void main(String[] args) { ThreadRunnableDemo tr = new ThreadRunnableDemo(); Thread t = new Thread(tr, "Thread 1"); t.start(); } @Override public void run() { System.out.println("Thread " + Thread.currentThread().getId() + " running"); System.out.println("Thread Name: " + Thread.currentThread().getName()); } }
Thread 12 running Thread Name: Thread 1
Pause a thread
The Thread class has an inbuilt method sleep()
that makes a thread pause the execution or sleep for a certain amount of specified time. The sleep() method accepts milliseconds as a parameter that makes the thread sleep for the mentioned parameter value. For example, if we mention 10000 milliseconds, it waits for 10 seconds before continuing the thread execution.
import java.util.Date; public class ThreadSleepDemo extends Thread { public void run() { System.out.println("Start time: " + java.util.Calendar.getInstance().getTime()); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Start time: " + java.util.Calendar.getInstance().getTime()); } public static void main(String[] args) { ThreadSleepDemo t = new ThreadSleepDemo(); t.start(); } }
Start time: Sat Feb 06 17:37:34 IST 2021 Start time: Sat Feb 06 17:37:44 IST 2021
Stop a thread execution
The built-in stop()
method of the Thread class is no more available and is deprecated. This is because it does not know in which thread state we are stoping the thread. Hence it can cause the application to stop or fail unexpectedly if other threads were holding the same resource where the current thread was stopped.
We can implement custom stop()
methods to create the actual behavior of stopping a thread. In the below example, we can see how to stop a thread execution using our own method.
We create a custom class ThreadStopDemo that implements the Runnable interface and then create a thread using this Runnable interface instance. We define a custom stop()
method that assigns the boolean stop variable with value as true. Hence whenever we call this stop method, it assigns this boolean value as true. We define another custom method running()
that assigns the same stop variable as false to continue the execution process. Now, in the run()
method, we call the running()
method that executes as long as the stop variable returns false. After executing for a while, we call the stop()
method from the main method that assigns the stop variable as true and hence stops the thread execution since the running()
method now returns false.
public class ThreadStopDemo implements Runnable{ private boolean stop = false; public synchronized void stop() { this.stop = true; System.out.println("Thread stopped"); } private synchronized boolean running() { return this.stop == false; } public static void main(String[] args) { ThreadStopDemo ts = new ThreadStopDemo(); Thread t = new Thread(ts); t.start(); try { Thread.sleep(10000); } catch(InterruptedException e) { e.printStackTrace(); } ts.stop(); } @Override public void run() { while(running()) { System.out.println("Thread running"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Thread running Thread running Thread running Thread stopped
Thread.currentThread()
The currentThread()
method of the Thread class returns the reference of the current thread in execution. We can access several properties of this current thread like getId(), getName(), getPriority(), etc
System.out.println("Thread " + Thread.currentThread().getId() + " running");
Thread methods examples
The below example shows how to set and retrieve various thread properties.
public class ThreadExample extends Thread{ public void run() { System.out.println("Thread running"); System.out.println("Thread state: " + Thread.currentThread().getState()); System.out.println("Is thread alive: " + Thread.currentThread().isAlive()); } public static void main(String[] args) { ThreadExample te = new ThreadExample(); Thread t = new Thread(te, "Thread1"); t.start(); System.out.println("Before setName - Thread name: " + t.getName()); System.out.println("Before set priority - Thread priority: " + t.getPriority()); t.setName("Thread demo"); t.setPriority(2); System.out.println("Thread id: " + t.getId()); System.out.println("After setName - Thread name: " + t.getName()); System.out.println("After set priority - Thread priority: " + t.getPriority()); System.out.println("Thread state: " + t.getState()); System.out.println("Is thread alive: " + t.isAlive()); System.out.println("Is it Daemon thread: " + t.isDaemon()); System.out.println("Is thread interrupted: " + t.isInterrupted()); } }
Before setName - Thread name: Thread1 Thread running Before set priority - Thread priority: 5 Thread id: 13 After setName - Thread name: Thread demo Thread state: RUNNABLE After set priority - Thread priority: 2 Is thread alive: true Thread state: RUNNABLE Is thread alive: false Is it Daemon thread: false Is thread interrupted: false
join() method
The join()
method of the Thread class waits for the thread to terminate. The main use of the join()
method is for inter-thread communication. The below example shows the usage of the join()
method.
public class ThreadJoinDemo extends Thread { public void run() { System.out.println("Thread running"); System.out.println("Is thread alive: " + Thread.currentThread().isAlive()); } public static void main(String[] args) throws InterruptedException { Thread t = new ThreadJoinDemo(); System.out.println("Thread created"); t.start(); System.out.println("Joining thread"); t.join(); System.out.println("Is thread alive: " + t.isAlive()); } }
Thread created Joining thread Thread running Is thread alive: true Is thread alive: false
Different types of thread
A thread can be of 2 types:
- User thread: The thread that we create is called a user thread. Each user thread has a specific task to do. The JVM shuts down only after it completes the execution of all the user threads. In other words, it waits for all the user threads to complete before it shuts down.
- Daemon thread: Daemon threads run in the background and are low priority threads. The JVM does not wait for the daemon threads to complete. It automatically shuts down when the user thread execution is complete.
Process vs Thread
Based On | Process | Thread |
---|---|---|
Basic | Process is an instance of a program in execution | Thread is a part of a process |
Address Space | Process has it own address space | Threads share same address space of a process |
Control Block | Process has its own Process Control Block (PCB). Process has global variables, child processes, signal handlers, accounting information and open files. | Threads have their own Thread Control Block. Which has a Program Counter, Stack Pointer, Registers. |
About | Process can have multiple threads | Thread is a small entity which can execute in parallel with other threads |
Weight | Process is heavy weight | Thread is a light weight process |
Overhead | Process has a heavy overhead | Thread has a less overhead |
Dependency | Processes are independent with each other | Threads share the same address space so they are not independent |
Synchronization | Synchronization is not required | Synchronization can be done in threads |
Communication | Process communicate with other processes using interprocess communication which is difficult. | Communication between threads can be done very easily because they share same address space |
Starting New | Starting a new process is different | Start a new thread is simple and it can be done calling new Thread method |
Context Switching | Context switching between processes is costly | Context switching between threads is less expensive |
Conclusion
This comes to the end of this tutorial where we have learned about threads, how to create a thread, its method, and thread lifecycle.