ADVENTURE ISLAND AT GOOGLE AS SANKALP SE SIDDHI BHARAT.

ADVENTURE ISLAND AT GOOGLE AS SANKALP SE SIDDHI BHARAT.
DR. PRERNA SAXENA IT WOMEN SCIENTIST and educationist from INDIA.

Thursday, December 18, 2025

MULTI THREADING IN JAVA

 

Your First Steps in Java Multithreading: Creating and Understanding Threads

Introduction: What is a Thread, and Why Should I Care?

Welcome to the fascinating world of multithreading in Java! If you're looking to take your programming skills to the next level, understanding how to manage multiple tasks at once is a crucial step.

In Java, multithreading is a powerful feature that allows your application to perform multiple tasks concurrently. Think of it as having several workers handling different jobs simultaneously instead of one worker doing everything sequentially. The primary benefits of this approach are significantly improved application performance and better utilization of your computer's resources.

This guide will walk you through the essentials, covering the two fundamental ways to create a thread and the journey it takes from birth to completion.

--------------------------------------------------------------------------------

1. The Two Fundamental Ways to Create a Thread in Java

Java provides two standard methods for creating a new thread of execution. Both achieve the same goal but have important differences in their design and flexibility. Let's explore both.

1.1. Method 1: Extending the Thread Class

The first method involves creating a new class that inherits directly from Java's built-in Thread class.

To do this, your new class must override the run() method. This method contains the code that will be executed when the thread starts—it's the heart of your thread's task.

class MyThread extends Thread {
    @Override
    public void run(){
        System.out.println("Thread is running");
    }
}
public class GFG {
    public static void main(String [] args){
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        t1.start();
        t2.start();
    }
}

To bring your thread to life, you create an instance of your custom thread class and call its start() method. The Java Virtual Machine (JVM) then calls the run() method in a new thread of execution.

1.2. Method 2: Implementing the Runnable Interface

The second, and more commonly used, method is to create a class that implements the Runnable interface.

Like the first method, this class must also provide an implementation for the run() method to define its task. However, because this class doesn't extend Thread, it doesn't represent a thread itself—it only represents a task that can be run by a thread.

To execute this task, you create an instance of your Runnable class and pass it into the constructor of a new Thread object.

class MyRunnable implements Runnable {
    @Override
    public void run()
    {
        System.out.println("Thread is running");
    }
}
public class GFG {
    public static void main(String [] args){
        MyRunnable task = new MyRunnable();
        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        t1.start();
        t2.start();
    }
}

Note that in this example, a single task object is shared by both t1 and t2. This is a key feature of the Runnable approach and directly relates to the resource sharing benefits we'll discuss next.

1.3. So, Which Method Should I Use?

While both approaches work perfectly well, implementing the Runnable interface is the generally recommended approach. This preference is based on principles of good object-oriented design and flexibility.

Here’s a breakdown of the key advantages of using Runnable:

Key Advantage

Why It Matters for New Programmers

Multiple Inheritance

Java classes can only extend one parent class. If you extend Thread, your class is "used up" and can't inherit from any other class. By implementing Runnable, your class is free to extend another class.

Resource Sharing

A single Runnable object can be passed to multiple Thread objects. This allows different threads to execute the same task, sharing the same data and reducing memory overhead.

Separation of Concerns

This is a core principle of good software design. Runnable separates the task (what to do) from the worker (the Thread that does it). This makes your code cleaner and more organized.

Flexibility

The Runnable interface is the foundation of modern Java concurrency frameworks, like the Executor framework, which provide powerful ways to manage pools of threads. Crucially, classes that extend Thread cannot be used directly with these powerful tools, making the Runnable approach far more versatile for building complex applications.

Key Takeaway: Implementing Runnable is more flexible and promotes better object-oriented design because it separates the what (the task) from the how (the thread execution).

Now that you know how to create a thread, let's explore what happens to it throughout its existence.

--------------------------------------------------------------------------------

2. The Journey of a Thread: Understanding its Lifecycle

Every thread in Java progresses through several distinct states from the moment it is created until it is completed. Understanding this lifecycle is essential for debugging and managing multithreaded applications effectively.

2.1. The Six States of a Thread

A Java thread can exist in one of six states at any given moment.

  1. New This is the initial state of a thread right after it has been created (e.g., Thread t1 = new Thread()) but before the start() method has been called on it. The thread exists but is not yet alive.
  2. Runnable A thread enters the Runnable state after its start() method is invoked. In this state, the thread is ready to run and is waiting for the thread scheduler to allocate CPU time. A thread in this state might be actively running or simply ready to run.
  3. Blocked A thread becomes Blocked when it tries to acquire a lock (for example, by entering a synchronized block) that is currently held by another thread. It remains blocked until the lock is released.
  4. Waiting A thread enters the Waiting state when it calls a method that causes it to wait indefinitely for another thread to perform a specific action. This happens after calling methods like Object.wait() or Thread.join() without a timeout.
  5. Timed Waiting This state is similar to Waiting, but the thread will only wait for a specified period. A thread enters this state after calling methods with a timeout, such as Thread.sleep(1000), Object.wait(500), or Thread.join(500).
  6. Terminated A thread enters the Terminated state once it has completed the execution of its run() method. This can happen either through normal completion or because an unhandled exception was thrown, abruptly ending its task.

2.2. Checking a Thread's State

Java provides a simple way to check the current state of a thread programmatically. You can do this by calling the Thread.getState() method on a thread instance, which returns an enum constant corresponding to one of the six states described above.

--------------------------------------------------------------------------------

3. Conclusion: Your Foundation in Java Threads

Congratulations on taking your first steps into Java multithreading! You've learned the two fundamental ways to create threads—by extending the Thread class and by implementing the Runnable interface—and, most importantly, why Runnable is the preferred, more flexible approach.

You also now understand that every thread has a lifecycle, moving through states like New, Runnable, and Terminated. This knowledge is the foundation for writing more complex, efficient, and responsive Java applications.

Keep experimenting with these concepts, and you'll be well on your way to mastering the world of Java concurrency.

No comments: