Thread in Java


Java ThreadViews 1957

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.

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.

Thread in Java

Java thread constructors

Below are the common constructors of the Java Thread class.

ConstructorDescription
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

MethodDescription
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.

Java Thread Lifecycle

 

  • 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 OnProcessThread
BasicProcess is an instance of a program in executionThread is a part of a process
Address SpaceProcess has it own address spaceThreads share same address space of a process
Control BlockProcess 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.
AboutProcess can have multiple threadsThread is a small entity which can execute in parallel with other threads
WeightProcess is heavy weightThread is a light weight process
OverheadProcess has a heavy overheadThread has a less overhead
DependencyProcesses are independent with each otherThreads share the same address space so they are not independent
SynchronizationSynchronization is not requiredSynchronization can be done in threads
CommunicationProcess 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 NewStarting a new process is differentStart a new thread is simple and it can be done calling new Thread method
Context SwitchingContext switching between processes is costlyContext 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.

Reference

Translate »