View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All

Thread in Java – Complete Beginner’s Guide with Examples

Updated on 19/05/20254,876 Views

Java supports the powerful multithreading concept, allowing multiple threads to run in parallel. This feature is essential for developing efficient, responsive, and real-time applications. Threads help perform background tasks like downloading files, processing data, or handling user inputs—without blocking the main application.

In this blog, you’ll learn what threads are in Java, how they work, how to create them, manage their lifecycle, and avoid common issues. We’ll also explore practical examples and real-world use cases to strengthen your understanding of multithreading in Java.

To master concepts like these, Software Engineering courses can provide structured learning and hands-on experience.

What is Thread in Java?

A thread in Java is a lightweight, independent path of execution within a program. While every Java application runs on at least one thread (the main thread), you can create additional threads to perform tasks concurrently. Java’s java.lang.Thread class and Runnable interface help create and manage threads easily.

Example:

public class MyThread extends Thread {
    public void run() {
        System.out.println("Thread is running");
    }

    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
    }
}

Output:

Thread is running

Explanation: This code creates a new thread using the Thread class. The run() method defines the task, and start() begins execution.

Master in-demand skills with these popular programs.

Concept of Multitasking

Multitasking means executing multiple tasks at the same time. In programming, this helps improve performance by utilizing CPU resources more efficiently. Java programming supports multitasking using two approaches: process-based and thread-based multitasking.

Let’s explore each type in detail.

Process-Based Multitasking

Process-based multitasking involves running multiple programs simultaneously. Each process has its own memory space and resources, isolating it from others. For example, playing music while writing an IDE code involves two processes.

In Java, process-based multitasking is handled by the operating system.

Thread-Based Multitasking

Thread-based multitasking is the ability to run multiple threads within a single process. Since threads share the same memory, they communicate faster but must be managed carefully to avoid conflicts. Java's multithreading feature falls under this category.

It’s used in real-world applications like web servers, gaming, or GUI programs where multiple tasks need to run concurrently.

Must explore: Thread Priority in Java

Life Cycle of a Thread

A Java thread goes through multiple states during its life span. These include New, Active, Blocked/Waiting, Timed Waiting, and Terminated. Understanding Life cycle of Thread helps in debugging and managing thread behavior.

Java Thread life Cycle

Let’s break down each state.

New State

A thread is in the New state when it is created but not yet started.

Example:

Thread t = new Thread();

Here, t is in the new state.

Active State

A thread becomes Active after calling start(). It includes two sub-states:

  • Runnable: Ready to run.
  • Running: Actually executing.

Example:

Thread t = new Thread(() -> System.out.println("Running"));
t.start();

Output:

Running

Waiting/Blocked State

A thread enters this state when it’s waiting for a resource or signal to continue execution.

Example:

synchronized(obj) {
    obj.wait();
}

Here, the thread waits until it’s notified.

Timed Waiting State

This state occurs when a thread waits for a specified amount of time.

Example:

Thread.sleep(2000);

Explanation: The thread pauses for 2 seconds.

Terminated State

When a thread completes its execution or is forcibly stopped, it enters the Terminated state.

Example:

public void run() {
    System.out.println("Done");
}

Once run() finishes, the thread is terminated.

Working of Thread States

The thread life cycle flows as: New → Runnable → Running → (Waiting/Timed Waiting/Blocked) → Terminated. Java’s Thread class provides methods like start(), sleep(), and join() to manage these transitions.

Understanding this flow is essential for writing efficient and bug-free multithreaded applications.

Creating a Thread in Java

Java provides two main ways to create a thread:

  1. By extending the Thread class
  2. By implementing the Runnable interface

Let’s understand both methods with syntax and examples.

Extending Thread Class

In this method, you create a new class that extends the built-in Thread class and override its run() method. When you call start(), it internally calls the run() method. This is simple but limits your class from extending any other class due to Java's single inheritance.

Syntax: 

class MyThread extends Thread {
    public void run() {
        System.out.println("Thread running");
    }
}

Example:

class MyThread extends Thread {
    public void run() {
        System.out.println("Thread is running using Thread class.");
    }

    public static void main(String[] args) {
        MyThread t1 = new MyThread();  
        t1.start();  // Starts the thread
    }
}

Output:

Thread is running using Thread class.

Explanation:

Here, the MyThread class extends Thread, and the run() method defines the task. Calling start() internally invokes run() in a new thread.

Implementing Runnable Interface

Here, you define a class that implements the Runnable interface and provide the logic inside the run() method. You then pass this object to a Thread instance and call start(). This approach is more flexible and preferred when your class needs to extend another class.

Syntax: 

class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Runnable running");
    }
}

Example:

class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Thread is running using Runnable interface.");
    }

    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread t1 = new Thread(runnable);  
        t1.start();  // Starts the thread
    }
}

Output:

Thread is running using Runnable interface.

Explanation:

Here, MyRunnable implements Runnable, and its run() method is passed to a Thread object. This approach is preferred when you want your class to extend another class.

Running Threads

After creating a thread, use the start() method to run it. This internally calls the run() method.

Example:

public class Demo {
    public static void main(String[] args) {
        Thread t = new Thread(() -> System.out.println("Running"));
        t.start();
    }
}

Output:

Running

Explanation: The lambda expression defines the task, and start() initiates the thread.

Concurrency Problems

When multiple threads access shared resources, concurrency issues like race conditions may occur. These can lead to unpredictable behavior and bugs.

Use synchronization to avoid such problems.

Example:

class Counter {
    int count = 0;

    synchronized void increment() {
        count++;
    }
}

Explanation: The synchronized keyword ensures only one thread accesses the method at a time.

Real-World Use Cases of Threads

Threads are used in many real-world Java applications:

  • Web Servers: Handle multiple client requests
  • Games: Manage rendering, input, and physics
  • Banking Apps: Process transactions simultaneously
  • Chat Applications: Allow messaging and status updates concurrently

Multithreading enhances performance and ensures responsive software.

Best Practices for Using Threads

  • Keep threads short-lived and specific
  • Avoid unnecessary synchronization
  • Use thread pools (ExecutorService) for better resource management
  • Handle exceptions properly within threads
  • Prefer java.util.concurrent package for advanced control

Conclusion

Thread in Java make programs more efficient, interactive, and responsive. Understanding thread creation, life cycle, and synchronization is crucial for building real-time and concurrent applications. By following best practices and mastering key concepts, you can handle complex tasks effectively.


FAQs

1. How is the start() method different from run() in Java threads?

Calling start() creates a new thread and executes the run() method on it. Calling run() directly doesn’t start a new thread—it just runs the code in the current thread like a normal method.

2. Can we restart a thread in Java once it has completed execution?

No, once a thread has finished execution and reached the terminated state, it cannot be restarted. You must create a new thread object to execute the task again.

3. What happens if we call the start() method twice on the same thread object?

Calling start() more than once on the same thread object throws an IllegalThreadStateException. A thread can only be started once. You’ll need to create a new thread instance to start again.

4. What is the difference between sleep() and wait() in Java?

sleep() is a static method of Thread used to pause execution for a specific time. wait() is from Object and is used for thread synchronization—it pauses until another thread calls notify() or notifyAll().

5. Why is the run() method not called directly to start a thread?

Calling run() directly doesn’t create a new thread; it just executes in the current thread. To achieve true multithreading, the start() method must be used, which internally calls run() in a new thread.

6. What is the use of join() method in Java threads?

The join() method makes one thread wait for another to complete its execution. It’s useful when the final result depends on the completion of another thread’s task.

7. Can we create a thread without using Thread or Runnable?

Yes, starting from Java 8, you can use lambda expressions with the Runnable interface. Internally, you still need to pass it to a Thread object to execute it.

8. What is thread starvation and how can it be avoided?

Thread starvation happens when low-priority threads don’t get CPU time because high-priority threads dominate. It can be avoided using fair thread scheduling with thread pools or proper synchronization techniques.

9. How are daemon threads different from user threads?

Daemon threads are background service threads that run until all user threads finish. They’re used for tasks like garbage collection. User threads are primary threads that keep the application running.

10. What is thread priority in Java and does it guarantee execution order?

Thread priority is a hint to the thread scheduler about the importance of threads, ranging from 1 (MIN) to 10 (MAX). However, it doesn’t guarantee execution order as scheduling is OS-dependent.

11. What are thread pools and why should we use them?

Thread pools manage a group of reusable threads, avoiding the overhead of creating and destroying threads repeatedly. They improve performance and are ideal for executing large numbers of short tasks efficiently using the ExecutorService.

image

Take the Free Quiz on Java

Answer quick questions and assess your Java knowledge

right-top-arrow
image
Join 10M+ Learners & Transform Your Career
Learn on a personalised AI-powered platform that offers best-in-class content, live sessions & mentorship from leading industry experts.
advertise-arrow

Free Courses

Explore Our Free Software Tutorials

upGrad Learner Support

Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)

text

Indian Nationals

1800 210 2020

text

Foreign Nationals

+918068792934

Disclaimer

1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.

2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.