top

Search

Java Tutorial

.

UpGrad

Java Tutorial

Thread in Java

Introduction

Java was introduced to the world for the first time in 1990. Since then, it has been widely used to create various applications. Naturally, the IT industry relies heavily on Java to offer its products to customers.

To become a successful computer science professional, it is necessary to grasp the fundamentals of Java. Thread in Java is one such topic that should be well comprehended if one wants to work as a computer scientist.

Overview

This article deals with several concepts in a Java Thread. It aims at covering the concepts of multitasking, the different types of multitasking, the creation of a thread in Java, how to create threads in Java, multithreading in Java, and much more. Read on to know more! 

The Concept Of Multitasking

  • Process-Based Multitasking

Multiple processes execute simultaneously in process-based multitasking. Each of them has to own instance of a program. In Java, one can carry out process-based multitasking using threads.

A thread is a lightweight process that exists within a process and shares its resources. Multiple threads can execute within a single program. This allows for concurrency.

Here is an example of process-based multitasking using threads in Java:

public class MyThread extends Thread {
    private String name;
    public MyThread(String name) {
        this.name = name;
    }
    public void run() {
        System.out.println("Thread " + name + " is running.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread " + name + " is finished.");
    }
}
public class Main {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread("Thread 1");
        MyThread thread2 = new MyThread("Thread 2");
        thread1.start();
        thread2.start();
    }
}
  • Thread-Based Multitasking

Thread-based multitasking is a type of multitasking. Here, multiple threads run together within a single process. In Java, you can create threads by extending the Thread class. Another way is by implementing the Runnable interface. 

Let us take a look at thread-based multitasking in Java:

class MyThread extends Thread {
    private String name;
    public MyThread(String name) {
        this.name = name;
    }
    public void run() {
        System.out.println("Thread " + name + " is running.");
        try {
            Thread.sleep(1000); // Sleep for 1 second
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread " + name + " is finished.");
    }
}
public class Main {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread("Thread 1");
        MyThread thread2 = new MyThread("Thread 2");
        thread1.start();
        thread2.start();
    }
}

What Is a Thread in Java?

A thread in Java is a lightweight sub-process or an independent path of execution within a program. A thread runs concurrently with other threads, sharing the same memory space and resources of the program. However, it can execute independently and parallelly with threads.

Each Java program starts with a main thread. This main thread creates and manages other threads as per need. Threads can be created by extending the “Thread” class or implementing the Runnable interface. The runnable interface provides a “run()” method that contains the code to be executed by the thread.

Java threads are commonly used in applications that must be executed simultaneously with multiple other tasks. Such tasks include user interfaces, network servers, and multimedia applications. Threads can significantly enhance the performance and responsiveness of an application. They do it by allowing it to execute multiple tasks simultaneously while sharing resources efficiently. 

Creating a Thread in Java

Why Are Threads Used?

Threads are used in Java to ensure concurrent execution of multiple tasks within a single program. They allow multiple parts of a program to run simultaneously. This makes the program more efficient and responsive. Some of the main reasons why threads are used in Java include:

  • Parallelism: Threads can be used to execute multiple tasks parallelly. This allows a program to use the system resources available efficiently.

  • Responsiveness: The main application thread can remain responsive and continue to handle user input when they run time-taking tasks in a separate thread. 

  • Simplified programming: Threads can simplify the programming of complex applications. This can be done by enabling different application parts to be coded independently. Then they can be executed parallelly. 

  • Asynchronous programming: Threads can be used to perform non-blocking I/O operations. This enhances the performance and responsiveness of applications to a great extent. These are the applications that need to interact with external systems.

Life Cycle Of Thread

New State

In Java, a new thread is in the "new" state when an instance of the “Thread” class is created. However, the “start()” method has not yet been called on that instance. In the "new" state, the thread is not considered alive. Therefore, it cannot be scheduled for execution.

Here is a thread in Java example in the "new" state:

public class MyThread extends Thread {
    private String name;
    public MyThread(String name) {
        this.name = name;
    }
    public void run() {
        System.out.println("Thread " + name + " is running.");
    }
    public static void main(String[] args) {
        MyThread thread = new MyThread("MyThread");
        System.out.println("Thread state: " + thread.getState()); // Output: "Thread state: NEW"
    }
}

Active State 

Here are the two active states of a thread in Java:

1. Runnable State

A thread is in the Runnable state when it has been started, is executing, or is ready to execute but has not been given CPU time yet.

2. Running State

In Java, the running state of a thread is when the Thread object's “run()” method is executed. In other words, the thread is actively performing its task.

Waiting/ Blocked State

A thread is in a Blocked state while waiting for a monitor lock to be released. This can happen when a thread tries to access a synchronized block of code currently being held by another thread.

Example:

Timed Waiting State

A thread in the "TIMED_WAITING" state is one in which a thread waits for a specific amount of time to elapse. This is either because it has called the “sleep() method” or because it is waiting for a lock to become available.

Here is an example code of a timed waiting thread in Java:

Terminated State

In Java, a thread enters the "Terminated" state when its “run() method” has completed execution and has stopped running. Once a thread enters the Terminated state, it cannot be restarted or resumed.

What is Main Thread?

The main thread is the first one created when a Java application commences. It is created by the Java Virtual Machine (JVM). It executes the “main()” method of the application. The main thread is slightly different from other threads since it is the only one to create other threads. The main thread terminates when the “main()” method completes. Then the JVM shuts down. This terminates all other threads that are still running.

The main thread can carry out activities such as initializing the application, creating other threads, and waiting for those threads to complete. It can also be used to handle uncaught exceptions that occur in other threads.

It is to be noted that the main thread is just like any other thread in Java. It can be controlled and manipulated in the same way. 

For instance, you can use the “Thread.sleep()” method to pause the main thread for a certain amount of time. Alternatively, you can use synchronization mechanisms to coordinate its execution with other threads.

How to Create Threads using Java Programming Language? 

Here are some ways how to create a thread in Java:

Extending Thread Class 

Here is an example code for creating a thread by extending the Thread class in Java:

public class MyThread extends Thread {
    public void run() {
        System.out.println("Thread is running.");
        for (int i = 0; i < 1000000000; i++) {
        }
    }
}
public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
    }
}

Implementing a Runnable Interface

Here is an example of creating a thread by implementing the Runnable interface in Java:

public class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Thread is running.");
        for (int i = 0; i < 1000000000; i++) {
        }
    }
}
public class Main {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

Java Thread Priorities

public class PriorityExample implements Runnable {
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println(Thread.currentThread().getName() + " is running: " + i);
        }
    }   
    public static void main(String[] args) {
        PriorityExample pe = new PriorityExample();      
        Thread t1 = new Thread(pe, "Thread 1");
        Thread t2 = new Thread(pe, "Thread 2");
        Thread t3 = new Thread(pe, "Thread 3");
        t1.setPriority(Thread.MIN_PRIORITY);
        t2.setPriority(Thread.NORM_PRIORITY);
        t3.setPriority(Thread.MAX_PRIORITY);
        t1.start();
        t2.start();
        t3.start();
    }
}

Most Commonly Used Constructors in Thread Class 

Here is an example code snippet showing some of the commonly used constructors in the Thread class:

public class ThreadConstructorsExample implements Runnable {
    public void run() {
        System.out.println("Thread is running.");
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(new ThreadConstructorsExample());
        t1.start();
        Thread t2 = new Thread(new ThreadConstructorsExample(), "MyThread");
        t2.start();
        Thread t3 = new Thread();
        t3.start();
        Thread t4 = new Thread("AnotherThread");
        t4.start();
    }
}

Multithreading in Java

Multithread in Java allows multiple threads to run concurrently within the same program. A thread is an independent unit of execution. This runs concurrently with other threads. They share the same resources, like memory and CPU time. In Java, threads can be created by extending the Thread class or implementing the Runnable interface.

How to Handle Thread Deadlock

A thread deadlock is a situation where two or more threads are blocked. This is because they are waiting for each other to release the resources that they need to proceed. In Java, deadlock can be handled in many ways. Some of the ways are as follows:

  • Avoiding circular wait: One way to prevent deadlock is to avoid acquiring locks on multiple resources in a circular manner. If multiple threads need multiple resources, they should acquire them in the same order to prevent a circular wait.

  • Using a timeout: You can use a timeout to avoid a thread being blocked indefinitely. You can mention a timeout value when acquiring locks on resources using the “tryLock()” method. The method will return false if it cannot acquire the lock within the timeout period. Then, the thread can move on to do other tasks.

  • Using thread interruption: You can interrupt a thread stuck in a deadlock by calling the “interrupt()” method on the thread. The interrupted thread will receive an “InterruptedException.” It can then decide how to handle it.

  • Using a deadlock detection algorithm: Some algorithms can detect if a deadlock has occurred in a program. One such algorithm is the wait-for-graph algorithm. This algorithm can detect circular dependencies. This can help to identify the resources and threads involved in the deadlock.

Methods of Thread Class

Here's an example that demonstrates some of the commonly used methods of the Thread class in Java:

public class ThreadMethodsExample extends Thread { 
    public void run() {
        System.out.println("Thread is running.");
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new ThreadMethodsExample();
        System.out.println("Thread name: " + t1.getName());
        t1.setName("MyThread");
        System.out.println("Thread name: " + t1.getName());
        System.out.println("Thread priority: " + t1.getPriority());
        t1.setPriority(Thread.MAX_PRIORITY);
        System.out.println("Thread priority: " + t1.getPriority());
        System.out.println("Is thread alive? " + t1.isAlive());
        t1.join();
        System.out.println("Is thread alive? " + t1.isAlive());
        System.out.println("Thread state: " + t1.getState());
    }
}

Conclusion 

This tutorial has discussed everything related to a thread in Java. We hope that this will act as a guide for your learning endeavors. Other than trying to master such areas from tutorials like these, you could also consider enrolling in a course that will prepare you to take on the challenges of the industry with ease. Online learning platforms like upGrad can help you become job-ready with industry-relevant curricula and real-world projects. 

FAQs

1. What is the difference between process and thread?

A process is an independent unit of execution. It has its own memory space. A thread is a lightweight process. This shares the same memory space as the parent process.

2. What is synchronization in Java?

Synchronization is the process of controlling access to shared resources. This is done in a multithreaded environment. In Java, synchronization is achieved using the “synchronized” keyword or locks.

3. What is a race condition in Java?

A race condition in Java occurs when two or more threads access a shared resource and try to modify it simultaneously. This might result in unpredictable behavior.

Leave a Reply

Your email address will not be published. Required fields are marked *