Posted on: January 18, 2025 Posted by: rahulgite Comments: 0

Threads in Java allow concurrent execution of two or more parts of a program, enabling multitasking and efficient resource usage.


1. What is a Thread in Java?

  • Definition: A thread is a lightweight sub-process, the smallest unit of processing.
  • Purpose: Enables a program to perform multiple tasks simultaneously.
  • Multithreading: A Java feature where multiple threads execute concurrently.

2. Lifecycle of a Thread

A thread in Java goes through the following states:

  1. New (Created):
    • A thread is created using the Thread class or implementing Runnable.
    • It remains in the new state until the start() method is called.
    Thread t = new Thread();
  2. Runnable:
    • After calling start(), the thread enters the runnable state, waiting for the CPU to schedule its execution.
    t.start();
  3. Running:
    • When the thread scheduler picks the thread, it enters the running state.
  4. Blocked/Waiting:
    • The thread is waiting for resources or other threads to complete.
  5. Terminated (Dead):
    • The thread finishes execution or is explicitly stopped.
    System.out.println("Thread finished.");

3. Creating Threads in Java

1. Extending the Thread Class

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

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

2. Implementing the Runnable Interface

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

public class RunnableExample {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());
        t.start();
    }
}

3. Using Lambda Expressions

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

4. Thread Class Methods

MethodDescription
start()Starts the thread and invokes the run() method.
run()Contains the code that constitutes the thread’s task.
sleep(long millis)Causes the thread to pause execution for the specified time in milliseconds.
join()Waits for the thread to finish execution.
getName()Returns the thread’s name.
setName(String name)Sets the thread’s name.
getPriority()Returns the thread’s priority.
setPriority(int p)Sets the thread’s priority (values between 1 and 10).
isAlive()Checks if the thread is alive.
yield()Hints the scheduler to allow other threads to execute.
interrupt()Interrupts the thread.

5. Thread Priority

  • Default Priority:
    • The default priority of a thread is 5 (NORM_PRIORITY).
  • Priority Levels:
    • MIN_PRIORITY: 1
    • NORM_PRIORITY: 5
    • MAX_PRIORITY: 10
  • High Priority: Threads with higher priority are given more CPU time by the thread scheduler.
  • Low Priority: Threads with lower priority are given less CPU time.

Example:

public class ThreadPriorityExample {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> System.out.println("Thread 1 running"));
        Thread t2 = new Thread(() -> System.out.println("Thread 2 running"));

        t1.setPriority(Thread.MIN_PRIORITY); // Priority 1
        t2.setPriority(Thread.MAX_PRIORITY); // Priority 10

        t1.start();
        t2.start();
    }
}

6. Thread Synchronization

Synchronization is used to control access to shared resources to prevent thread interference.

Example: Synchronized Method

class Table {
    synchronized void printTable(int n) {
        for (int i = 1; i <= 5; i++) {
            System.out.println(n * i);
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class MyThread extends Thread {
    Table table;

    MyThread(Table table) {
        this.table = table;
    }

    public void run() {
        table.printTable(5);
    }
}

public class SynchronizationExample {
    public static void main(String[] args) {
        Table table = new Table();
        MyThread t1 = new MyThread(table);
        MyThread t2 = new MyThread(table);
        t1.start();
        t2.start();
    }
}

7. Inter-thread Communication

Threads communicate using methods like wait(), notify(), and notifyAll().

Example:

class Chat {
    boolean flag = false;

    public synchronized void question(String msg) {
        if (flag) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(msg);
        flag = true;
        notify();
    }

    public synchronized void answer(String msg) {
        if (!flag) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(msg);
        flag = false;
        notify();
    }
}

public class InterThreadCommunication {
    public static void main(String[] args) {
        Chat chat = new Chat();

        new Thread(() -> {
            String[] questions = {"Hi", "How are you?", "Bye"};
            for (String question : questions) {
                chat.question(question);
            }
        }).start();

        new Thread(() -> {
            String[] answers = {"Hello", "I'm fine", "Goodbye"};
            for (String answer : answers) {
                chat.answer(answer);
            }
        }).start();
    }
}

8. Daemon Threads

  • Definition: Threads that provide background services and do not prevent the JVM from exiting.
  • Example: Garbage collection threads.
  • Setting a Daemon Thread:
Thread t = new Thread(() -> System.out.println("Daemon thread"));
t.setDaemon(true);
t.start();

9. Thread Pooling

  • Definition: A pool of threads that can be reused to execute tasks.
  • Advantage: Reduces overhead of thread creation and destruction.

Example:

import java.util.concurrent.*;

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);

        for (int i = 1; i <= 5; i++) {
            int taskId = i;
            executor.execute(() -> {
                System.out.println("Task " + taskId + " is running." + Thread.currentThread().getName());
            });
        }

        executor.shutdown();
    }
}

10. Advantages of Multithreading

  1. Improved Performance: Efficient CPU utilization.
  2. Resource Sharing: Multiple threads share common resources.
  3. Concurrency: Multiple tasks run simultaneously.
  4. Reduced Response Time: Faster execution of independent tasks.

11. Common Issues in Multithreading

  1. Deadlock:
    • Occurs when two or more threads wait indefinitely for each other to release resources.
  2. Race Condition:
    • Multiple threads accessing shared resources simultaneously, leading to inconsistent results.
  3. Thread Interference:
    • Threads modify shared resources unpredictably.
  4. Starvation:
    • A thread is perpetually denied access to resources.

Conclusion

Threads in Java enable concurrent programming, making applications efficient and responsive. Understanding thread lifecycle, synchronization, inter-thread communication, and thread pooling is essential for writing robust multithreaded applications.

Leave a Comment