Log In

Don't have an account? Sign up now

Lost Password?

Sign Up

Prev Next

Multithreading

Multithreading is a core feature of Java that allows a program to execute multiple tasks concurrently. Each task runs in a separate thread but shares the same process memory. Multithreading improves performance, responsiveness, and resource utilization, especially in applications like web servers, games, banking systems, and real-time systems.


1. Thread Lifecycle

A thread goes through different states during its execution. This sequence is called the thread lifecycle.

Thread States

  1. New
    • Thread is created but not started
  2. Runnable
    • Thread is ready to run or running
  3. Blocked / Waiting
    • Thread is waiting for a resource or signal
  4. Timed Waiting
    • Thread is sleeping or waiting for a specific time
  5. Terminated
    • Thread execution completed
New → Runnable → Running → Waiting/Blocked → Runnable → Terminated

Example

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

    public static void main(String[] args) {
        Demo t = new Demo(); // New
        t.start();           // Runnable
    }
}

2. Creating Threads in Java

Java provides two main ways to create threads.


2.1 Extending Thread Class

  • Thread class provides built-in thread functionality
  • Override the run() method

Example

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

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

2.2 Implementing Runnable Interface

  • Better approach (supports multiple inheritance)
  • Runnable object passed to Thread constructor

Example

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

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

Thread vs Runnable

ThreadRunnable
Extends classImplements interface
No multiple inheritanceSupports multiple inheritance
Less flexibleMore preferred

3. Thread Methods

3.1 start()

Starts a new thread and invokes run() internally.

t.start();

3.2 sleep()

Pauses thread execution for a specified time.

Thread.sleep(1000); // 1 second

3.3 join()

Makes one thread wait until another thread finishes.

t.join();

3.4 interrupt()

Interrupts a sleeping or waiting thread.

t.interrupt();

Example Using Methods

class Test extends Thread {
    public void run() {
        try {
            Thread.sleep(500);
            System.out.println("Thread executed");
        } catch (InterruptedException e) {
            System.out.println("Thread interrupted");
        }
    }

    public static void main(String[] args) throws Exception {
        Test t = new Test();
        t.start();
        t.join();
        System.out.println("Main thread ends");
    }
}

4. Synchronization and Thread Safety

What is Synchronization?

Synchronization ensures that only one thread accesses shared resources at a time, preventing data inconsistency.

Why Needed?

  • To avoid race conditions
  • To ensure data integrity

Synchronized Method Example

class Counter {
    int count = 0;

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

Synchronized Block Example

synchronized(this) {
    count++;
}

5. Inter-Thread Communication

Threads communicate using:

  • wait()
  • notify()
  • notifyAll()

These methods are defined in Object class.


Example

class Chat {
    synchronized void question(String msg) {
        System.out.println(msg);
        notify();
        try {
            wait();
        } catch (Exception e) {}
    }

    synchronized void answer(String msg) {
        System.out.println(msg);
        notify();
        try {
            wait();
        } catch (Exception e) {}
    }
}

6. ExecutorService and Thread Pools

What is ExecutorService?

ExecutorService manages a pool of threads and executes tasks efficiently without creating threads manually.

Benefits

  • Better performance
  • Thread reuse
  • Controlled thread creation

Example

import java.util.concurrent.*;

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

        executor.submit(() -> {
            System.out.println("Task executed by thread pool");
        });

        executor.shutdown();
    }
}

7. Callable and Future

Callable Interface

  • Similar to Runnable
  • Returns a result
  • Can throw exceptions
Callable<Integer> task = () -> 10 + 20;

Future Interface

  • Holds result of Callable
  • Used to retrieve result later

Example

import java.util.concurrent.*;

public class CallableDemo {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        Callable<Integer> task = () -> {
            Thread.sleep(500);
            return 100;
        };

        Future<Integer> future = executor.submit(task);

        System.out.println("Result: " + future.get());

        executor.shutdown();
    }
}

Runnable vs Callable

RunnableCallable
No return valueReturns value
Cannot throw checked exceptionCan throw exception
run()call()

Example:

java

// Method 1: Extending Thread class
class MyThread extends Thread {
    private String name;
    
    public MyThread(String name) {
        this.name = name;
    }
    
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println(name + " - Count: " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

// Method 2: Implementing Runnable
class MyRunnable implements Runnable {
    private String name;
    
    public MyRunnable(String name) {
        this.name = name;
    }
    
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println(name + " - Count: " + i);
        }
    }
}

// Synchronization example
class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
    
    public int getCount() {
        return count;
    }
}

public class MultithreadingDemo {
    public static void main(String[] args) throws InterruptedException {
        // Creating threads
        MyThread t1 = new MyThread("Thread-1");
        MyThread t2 = new MyThread("Thread-2");
        
        t1.start();
        t2.start();
        
        // Using Runnable
        Thread t3 = new Thread(new MyRunnable("Runnable-1"));
        t3.start();
        
        // Lambda expression with Runnable
        Thread t4 = new Thread(() -> {
            System.out.println("Lambda thread executing");
        });
        t4.start();
        
        // Join example
        t1.join();  // Wait for t1 to complete
        System.out.println("Thread-1 has finished");
        
        // Synchronization demo
        Counter counter = new Counter();
        Thread inc1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });
        
        Thread inc2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });
        
        inc1.start();
        inc2.start();
        inc1.join();
        inc2.join();
        
        System.out.println("Final count: " + counter.getCount());
    }
}

Leave a Comment

    🚀 Join Common Jobs Pro — Referrals & Profile Visibility Join Now ×
    🔥